编译器如何识别字节移位运算符的长度
How compilers identify the length of byte shift operators
考虑以下行:
int mask = 1 << shift_amount;
我们知道 mask
是 4 个字节,因为它被显式声明为 int
,但是这个要移位的 1
的长度未知。如果编译器将类型选择为 char
,它将是 8 位,或者它可能是 unsigned short
,大小为 16 位,因此移位结果实际上取决于编译器决定如何处理该 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 中说:
Each constant has a type, determined by its form and value, as detailed later.
这意味着我们总是可以从常量本身的文本中判断常量的类型是什么,而不考虑它出现在其中的表达式。(这里,“常量”实际上是一个字面意思:A thing whose值由其文本给出。例如 34
和 'A'
字面上表示数字 34 和字符 A,与引用某个对象的标识符 foo
形成对比。)
(这个答案专门针对 C。下面描述的规则在 C++ 中是不同的。)
6.4.4 的子条款详细说明了各种常量(整数、浮点数、枚举和字符)。可以用 int
表示的没有后缀的整数常量是 int
,因此 1
是 int
.
如果整数常量有后缀或不适合 int
,则其类型受其后缀、其值以及它是十进制、八进制还是十六进制的影响,根据 a table 6.4.4.1 5.
浮点常量如果没有后缀则为 double
,float
带有 f
或 F
,long double
带有 l
或 L
.
枚举常量(用 enum
声明)的类型为 int
。 (而且这些不是我上面描述的直接文字,因为它们是值的名称,但名称确实通过 enum
声明指示值。)
没有前缀的字符常量的类型为 int
。前缀为 L
、u
或 U
的常量的类型分别为 wchar_t
、char16_t
或 char32_t
。
考虑以下行:
int mask = 1 << shift_amount;
我们知道 mask
是 4 个字节,因为它被显式声明为 int
,但是这个要移位的 1
的长度未知。如果编译器将类型选择为 char
,它将是 8 位,或者它可能是 unsigned short
,大小为 16 位,因此移位结果实际上取决于编译器决定如何处理该 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 中说:
Each constant has a type, determined by its form and value, as detailed later.
这意味着我们总是可以从常量本身的文本中判断常量的类型是什么,而不考虑它出现在其中的表达式。(这里,“常量”实际上是一个字面意思:A thing whose值由其文本给出。例如 34
和 'A'
字面上表示数字 34 和字符 A,与引用某个对象的标识符 foo
形成对比。)
(这个答案专门针对 C。下面描述的规则在 C++ 中是不同的。)
6.4.4 的子条款详细说明了各种常量(整数、浮点数、枚举和字符)。可以用 int
表示的没有后缀的整数常量是 int
,因此 1
是 int
.
如果整数常量有后缀或不适合 int
,则其类型受其后缀、其值以及它是十进制、八进制还是十六进制的影响,根据 a table 6.4.4.1 5.
浮点常量如果没有后缀则为 double
,float
带有 f
或 F
,long double
带有 l
或 L
.
枚举常量(用 enum
声明)的类型为 int
。 (而且这些不是我上面描述的直接文字,因为它们是值的名称,但名称确实通过 enum
声明指示值。)
没有前缀的字符常量的类型为 int
。前缀为 L
、u
或 U
的常量的类型分别为 wchar_t
、char16_t
或 char32_t
。