c标准和位移位
这个问题最初是由该代码的(意外)结果启发而来的:c标准和位移位,c,standards,bit-shift,C,Standards,Bit Shift,这个问题最初是由该代码的(意外)结果启发而来的: uint16_t t16 = 0; uint8_t t8 = 0x80; uint8_t t8_res; t16 = (t8 << 1); t8_res = (t8 << 1); printf("t16: %x\n", t16); // Expect 0, get 0x100 printf(" t8: %x\n", t8_res); // Expect 0, get 0 为什么(t8我认为你困
uint16_t t16 = 0;
uint8_t t8 = 0x80;
uint8_t t8_res;
t16 = (t8 << 1);
t8_res = (t8 << 1);
printf("t16: %x\n", t16); // Expect 0, get 0x100
printf(" t8: %x\n", t8_res); // Expect 0, get 0
为什么(t8我认为你困惑的根源可能是以下两种说法不相等:
t64 = (uint64_t) (((int) t64) << 31);
- 每个操作数应为整数类型
- 每个操作数应具有
类型int
uint64\u t
是一个整数类型。您在标准中发现了错误的规则:(相关规则类似于“通常的整数类型促销适用”。这就是第一个示例的要点。如果像uint8_t
这样的整数类型的秩小于int
,它将升级为int
uint64_t
没有小于int
或unsigned
的秩,因此不会执行升级,并且将遵守§6.5.7中的约束“每个操作数都应具有整数类型。”这是一个约束,意味着您不能对非整数类型(如浮点值或指针)使用按位移位运算符。它不会造成您注意到的效果
造成影响的部分在下一段中:
3.对每个操作数执行整数提升。结果类型为提升后的左操作数
整数促销如§6.3.1.1所述:
2.如果int
或者可以使用无符号整数
:
- 具有整数类型的对象或表达式,其整数转换秩小于或等于
的秩,并且int
无符号整数
- 类型为
、\u Bool
、int
或有符号int
的位字段无符号int
int
可以表示原始类型的所有值,则该值
将转换为int
;否则,将转换为无符号
int
。这些被称为整数促销。所有其他类型都是
整数促销保持不变
uint8\u t
的等级低于int
,因此该值被转换为int
(因为我们知道int
必须能够表示uint8\u t
的所有值,考虑到这两种类型范围的要求)
排名规则很复杂,但它们保证具有较高排名的类型不能具有较低的精度。这意味着,实际上,不能通过整数提升将类型“降级”为精度较低的类型(可以将uint64\u t
提升为int
或无符号int
,但前提是类型的范围至少为uint64\u t
)
在
uint32\t的情况下,我不太明白为什么你说//在第二次左移31位后,我会感到困惑,因为格雷格是,但我希望类型永远不会自动降级(缩小),只会升级(扩大)。根据我对标准的理解,t64=(uint64\t)((int)t64)N1124由C99标准组成,其中合并了前两个技术勘误。是相同的,但与所有三个TC相同。(没有重大差异。)确实,这是OP混淆的根源。@Pat:注意,uint8\u t
也是一个整数类型,因此此规则对您在第一个示例中看到的行为不负责。正如所述,正是“常用算术转换”导致类型小于int
的值被提升(至int
或无符号
)@caf阅读了Jens的评论后,我进一步修改了问题。有什么进一步的见解吗?编辑的主要问题,因为评论中不允许换行,请看一看?啊……第6.3.1.1节第2节的最后一点对我来说真的很重要。还有你最后的总结规则。我的C思维模式更像是“按需促销”(因此在结尾附加了uint8_t问题)。这个答案很有道理,谢谢你抽出时间。-帕特
{
uint64_t t64 = 1;
t64 <<= 31;
printf("t64: %lx\n", t64); // Expect 0x80000000, get 0x80000000
t64 <<= 31;
printf("t64: %lx\n", t64); // Expect 0x0, get 0x4000000000000000
}
t64 = (uint64_t) (((int) t64) << 31);
uint32_t << uint64_t
uint32_t t32 = 1;
uint64_t t64_one = 1;
uint64_t t64_res;
t64_res = t32 << t64_one;
{
uint16_t t16 = 0;
uint8_t t8 = 0x80;
uint8_t t8_one = 1;
uint8_t t8_res;
t16 = (t8 << t8_one);
t8_res = (t8 << t8_one);
printf("t16: %x\n", t16);
printf(" t8: %x\n", t8_res);
}
t16: 100
t8: 0
uint32_t t32 = 1;
uint64_t t64_one = 1;
uint64_t t64_res;
t64_res = t32 << t64_one;
uint32_t t32 = 0xFF000;
uint64_t t64_shift = 16;
uint64_t t64_res;
t64_res = t32 << t64_shift;