编译器如何识别字节移位运算符的长度

问题描述

考虑以下行:

int mask = 1 << shift_amount;

我们知道 mask 是 4 个字节,因为它被显式声明为 int,但是这个要移位的 1 的长度未知。如果编译器选择类型为 char,它将是 8 位,或者它可能是 unsigned short 大小为 16 位,因此移位结果实际上将取决于编译器关于如何处理 1 的决定的大小{1}}。编译器在这里如何决定?以这种方式保留代码是否安全,或者应该改为:

int flag = 1;

int mask = flag << shift_amount;

解决方法

1 是一个 int(通常为 4 个字节)。如果您希望它是 int 以外的类型,您可以使用后缀,例如 1L 代表 long。如需了解详情,请参阅https://en.cppreference.com/w/cpp/language/integer_literal

您也可以使用像 (long)1 这样的演员表,或者如果您想要一个已知的固定长度,(int32_t)1

正如 Eric Postpischil 在评论中指出的那样,小于 int 的值(如 (short)1)没有用,因为 << 的左侧参数无论如何都会提升为 int .

,

2018 C 标准在 6.4.4 3 中说:

每个常量都有一个类型,由其形式和值决定,详情见后。

这意味着我们总是可以通过常量本身的文本来判断常量的类型,而无需考虑它出现的表达式。(这里,“常量”实际上是指字面量:值是由其文本给出。例如,34'A' 字面上表示数字 34 和字符 A,与引用某个对象的标识符 foo 相反。)

(这个答案专门针对 C。下面描述的规则在 C++ 中是不同的。)

6.4.4 的子条款详细说明了各种常量(整数、浮点数、枚举和字符)。可以用 int 表示的没有后缀的整数常量是 int,所以 1int

如果整数常量有后缀或不适合 int,则其类型受后缀、值以及是十进制、八进制还是十六进制的影响,根据表6.4.4.1 5.

浮点常量是 double,如果它们没有后缀,float 带有 fFlong double 带有 lL

枚举常量(用 enum 声明)的类型为 int。 (这些不是我上面描述的直接文字,因为它们是值的名称,但名称确实通过 enum 声明指示了值。)

没有前缀的字符常量的类型为 int。带有前缀 LuU 的常量的类型分别为 wchar_tchar16_tchar32_t