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

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

// 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 ) ); 

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

如果variable是有符号整数类型(例如, int )并且其值是

  • 负?

标准对此有何看法?

PS而且, 是的 ,我对CC++都感兴趣,请不要告诉我他们是不同的语言,因为我知道这个:)

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

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

标准:n3337 C ++ 11

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

5.8移位运算符[expr.shift]

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

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

出于同样的原因,我认为按位and / or negate是可以的:它们是数学定义的。

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

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

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

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

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

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

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

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

除非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 

5.8 Shift Operators C ++标准中的5.8 Shift Operators也说明了这一点:

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

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

C11在6.5.7 Bitwise shift operators ,除了其他东西,这个:

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

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

因此,整数的一般答案是:

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

如果你转移负数(或签名)数字(通过大多数实现是相同的U2事物),它是特定的实现。 如果您将无符号数字移动不超过变量中位数的值,则它对于大多数用途都是可移植的。