用于位操作的标准(跨平台)方式

Kir*_*rov 11 c c++ standards cross-platform bit-manipulation

由于是数字的不同二进制表示(例如,采取大/小端),这是跨平台:

// NOTE: FIXED-SIZE unsigned integral type
some_unsigned_type variable = some_number;

// set n-th bit, starting from 1,
// right-to-left (least significant-to most significant)
variable |= ( 1 << ( n - 1 ) );

// clear the same bit:    
variable &= ~( 1 << ( n - 1 ) );
Run Code Online (Sandbox Code Playgroud)

换句话说,编译器是否总是处理固定大小的无符号数的不同二进制表示,或者它是特定于平台的?

如果variable是有符号整数类型(例如int),它的值是

  • 负?

什么是标准说这个?

PS和,是的,我在这两个很有趣的- C并且C++,请不要告诉我,他们在不同的语言,因为我知道这:)

如果需要,我可以粘贴真实的例子,但帖子会变得太长

Seb*_*ach 6

除非some_unsigned_type是固定宽度类型,否则这是您的第一个特定平台.在一个平台上,您可能会转移一些永远不会被价值本身重现的信息,而在另一个平台上则可能没有.例:

16 bit 'int':

      1000 0000  0000 0000
<<1 = 0000 0000  0000 0000
>>1 = 0000 0000  0000 0000

32 bit 'int':

      0000 0000  0000 0000   1000 0000  0000 0000
<<1 = 0000 0000  0000 0001   0000 0000  0000 0000
>>1 = 0000 0000  0000 0000   1000 0000  0000 0000
Run Code Online (Sandbox Code Playgroud)

5.8 Shift Operators 在C++标准中也说过:

如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.

因此,如果将整数移位的位数多于输入的位数,则输入未定义的行为.例如,如果你将一个short值左移17位,它可能会在某些机器上给你UB,但不是全部.

6.5.7 Bitwise shift operators除了其他事情,C11说:

结果E1 >> E2E1右移位E2位置.如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是商的整数部分E1 / 2E2.如果E1具有有符号类型和负值,则结果值是实现定义的.

因此,签名号码转换不可移植.

所以,一般为整数的回答一般 是:

对整数的按位操作不可移植.


Mat*_* M. 5

免责声明:我隐含地假设您正在谈论具有固定宽度的整数类型.否则位移非常危险......

标准:n3337 C++ 11

对于无符号类型或有符号类型(*)中的正值,移位的定义是数学的,因此不受底层硬件表示的影响.

5.8移位运算符[expr.shift]

2E1 << E2E1左移位E2位置; 空位是零填充的.如果E1具有无符号类型,则结果的值E1 × 2E2将比结果类型中可表示的最大值模数减1.否则,如果E1有一个有符号类型和非负值,并且E1×2E2在结果类型中可表示,那么这就是结果值; 否则,行为未定义.

3E1 >> E2E1右移位E2位置.如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是商的整数部分E1/2E2.如果E1具有有符号类型和负值,则结果值是实现定义的.

出于同样的原因,我会认为按位and,or并且negate没关系:它们是数学定义的.

5.3.1一元运算符[expr.unary.op]

10操作数˜应具有整数或无范围的枚举类型; 结果是其操作数的一个补码.

5.11按位AND运算符[expr.bit.and]

1执行通常的算术转换; 结果是操作数的按位AND功能.运算符仅适用于整数或无范围的枚举操作数.

5.13按位包含OR运算符[expr.or]

1执行通常的算术转换; 结果是其操作数的按位包含OR函数.运算符仅适用于整数或无范围的枚举操作数.

但是我承认我对后两者不太确定,我找不到任何按位XX函数的定义,所以即使我相信他们指的是数学对应物,我也无法保证.

(*)感谢phresnel指出这一点.