15

我注意到许多 C/C++ 程序员使用如下方式实现标志集:

#define FLAG_1 (1 << 0)
#define FLAG_2 (1 << 1)
#define FLAG_3 (1 << 2)

unsigned int my_flags = 0; /* no flag set */
my_flags |= FLAG_2; /* set flag 2 */

但这种方法真的合理吗?在我看来,它似乎是在假设不属于 C/C++ 语言标准的无符号整数的二进制表示。例如,那个“0”实际上是0x0000。

我错了吗?或者我在理论上是对的,但在当前标准硬件的情况下实际上不是?

4

4 回答 4

20

C++

C++11 标准的重要部分是 §3.9.1/7 ( ISO/IEC 14882:2011(E) ):

整数类型的表示应使用纯二进制计数系统定义值。

这在脚注中得到了澄清:

49) 使用二进制数字 0 和 1 的整数的位置表示,其中由连续位表示的值是相加的,从 1 开始,并乘以 2 的连续整数幂,可能最高位置的位除外. (改编自美国国家信息处理系统词典。)

移位运算符的结果以数学方式定义。例如,对于E1 << E2

如果 E1 具有无符号类型,则结果的值为 E1 × 2 E2,比结果类型中可表示的最大值多模一减少。否则,如果 E1 具有带符号类型和非负值,并且 E1 × 2 E2在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。

位运算符具体定义为按位。例如,对于按位或:

执行通常的算术转换;结果是操作数的按位异或函数。

当然,在 as-if 规则下,表示不一定是纯二进制计数系统。编译器必须只生成一个它一样运行的程序。

C

在 C99 ( ISO/IEC 9899:TC3 ) 中,仅对位域和类型对象unsigned char(§6.2.6.1/3) 保证纯二进制表示法:

存储在无符号位域和无符号字符类型对象中的值应使用纯二进制表示法表示。

在脚注中再次澄清:

整数的位置表示,它使用二进制数字 0 和 1,其中由连续位表示的值是相加的,从 1 开始,并乘以 2 的连续整数幂,可能位置最高的位除外。(改编自美国国家信息处理系统词典。)

该标准特别指出按位运算取决于内部表示(§6.5/4):

某些运算符(一元运算符 ~ 和二元运算符 <<、>>、&、^ 和 |,统称为按位运算符)需要具有整数类型的操作数。这些运算符产生的值取决于整数的内部表示,并且具有符号类型的实现定义和未定义方面。

于 2012-10-02T18:24:39.903 回答
13

虽然理论上可以在使用非 2 次幂运算的架构上运行 C 或 C++,但|&^运算符被定义为具有按位行为,因此这样的机器需要模拟二进制运算。

因此,它是完全安全和便携的。

于 2012-10-02T18:21:50.400 回答
7

当前的 C 和 C++ 标准都将无符号整数表示形式限制为纯二进制表示形式,因此您上面的内容是完全安全的,并且可以保证工作。

于 2012-10-02T18:21:32.887 回答
2

向右位移总是会减小整数的值,而向左位移总是会增大整数的值。这与机器的字节序无关,所以要回答你的问题:“是的,这是合理的,因为无论系统的字节序如何,位移都是一样的”

这是否回答你的问题?

于 2012-10-02T18:21:33.120 回答