这个问题首先受到以下代码的(意外)结果的启发: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 0x100printf(" t8: %x\n", t8_res); // Expect 0, get 0但是事实证明这是有道理的: 6.5.7按位移位运算符约束条件 2 每个操作数应具有整数类型因此,最初混淆的行等效于:t16 = (uint16_t) (((int) t8) << 1);有点不直观的恕我直言,但至少是明确定义的。好的,很好,但是我们这样做:{uint64_t t64 = 1;t64 <<= 31;printf("t64: %lx\n", t64); // Expect 0x80000000, get 0x80000000t64 <<= 31;printf("t64: %lx\n", t64); // Expect 0x0, get 0x4000000000000000}//编辑:遵循与上述相同的文字参数,以下内容应等效:t64 = (uint64_t) (((int) t64) << 31);//因此,我的困惑/期望[end_edit]现在,我们得到了直观的结果,但不是从我(标准)阅读的标准中得出的结果。此“进一步的自动类型升级”何时/如何进行?还是在其他地方存在某种限制,那就是永远不能降级某种类型(这有意义吗?),在这种情况下,促销规则如何适用:uint32_t << uint64_t由于该标准确实说两个论点都被提升为int。应该在这里将两个参数提升为相同类型吗?//编辑:更具体地说,应得出以下结果:uint32_t t32 = 1;uint64_t t64_one = 1;uint64_t t64_res;t64_res = t32 << t64_one;//结束编辑当我们认识到该规范不要求专门升级到int而不是utt64_t合格的integer type时,就可以解决上述问题的答案。//澄清度编辑:好的,但是现在我又感到困惑了。具体来说,如果uint8_t是整数类型,那么为什么将其完全提升为int?它似乎与常量int 1无关,如以下练习所示:{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如果uint8_t是整数类型,为什么会提升(t8 --作为引用,我使用的是ISO/IEC 9899:TC9,WG14/N1124,2005年5月6日。如果这已经过时,并且有人还可以提供指向最新副本的链接,也将不胜感激。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 §6.5.7中的约束要求“每个操作数应具有整数类型”。是一个约束,这意味着您不能在非整数类型(如浮点值或指针)上使用按位移位运算符。它不会引起您所注意的效果。下一节中确实会造成影响的部分: 3. The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.整数促销在§6.3.1.1中进行了描述: 2. The following may be used in an expression wherever an int or unsigned int may be used: An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int. A bit-field of type _Bool, int, signed int, or unsigned int. If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.uint8_t的等级比int小,因此该值将转换为int(因为我们知道int必须能够表示uint8_t的所有值,这取决于这两种类型的范围要求)。排名规则很复杂,但是它们可以保证排名较高的类型的精度不会降低。实际上,这意味着不能通过整数提升将类型“降级”为精度较低的类型(可以将uint64_t提升为int或unsigned int,但前提是该类型的范围至少为uint64_t)。对于uint32_t << uint64_t,插入的规则是“结果的类型是提升后的左操作数的类型”。因此,我们有几种可能性:如果int至少为33位,则uint32_t将提升为int,结果将为int; 如果int小于33位,而unsigned int至少为32位,则uint32_t将提升为unsigned int,结果将为unsigned int; 如果unsigned int小于32位,则uint32_t将保持不变,结果将为uint32_t。 在当今常见的台式机和服务器实现中,int和unsigned int通常为32位,因此第二种可能性将会发生(uint32_t提升为unsigned int)。在过去,int/unsigned int通常为16位,并且第三种可能性会发生(不提倡uint32_t)。您的示例结果:uint32_t t32 = 1;uint64_t t64_one = 1;uint64_t t64_res;t64_res = t32 << t64_one;将值2存储到t64_res中。请注意,尽管这不受表达式结果不是uint64_t的事实的影响-受影响的表达式示例为:uint32_t t32 = 0xFF000;uint64_t t64_shift = 16;uint64_t t64_res;t64_res = t32 << t64_shift;这里的结果是0xf0000000。请注意,尽管细节相当复杂,但您可以将其简化为一个应记住的相当简单的规则: In C, arithmetic is never done in types narrower than int / unsigned int. (adsbygoogle = window.adsbygoogle || []).push({}); 10-06 04:09