c++中位操作符的定义是什么?

undefined behavior - What is the definition of bitwise operators in C++?

本文关键字:定义 是什么 操作符 位操作 c++      更新时间:2023-10-16

根据标准,操作符<<对第一个负号操作数产生未定义行为。

c++ 11 5.8.2

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-
filled. If E1 has an unsigned type, the value of the result is E1 × 2 pow E2,
reduced modulo one more than the maximum value representable in the result type.
Otherwise, if E1 has a signed type and non-negative value, and E1 × 2 pow E2 is
representable in the result type, then that is the resulting value; otherwise,
the behavior is undefined

这是可以理解的,因为内存中的整数布局是由实现定义的。

c++ 11 3.9.1.7

this International Standard permits 2’s complement, 1’s complement and
signed magnitude representations for integral types.

另一方面,标准似乎没有确切定义按位&

5.11位与运算符
and-expression:
    equality-expression
    and-expression & equality-expression
1 The usual arithmetic conversions are performed; the result is the bitwise 
AND function of the operands. The operator applies only to integral
or unscoped enumeration operands.

c++ 11 5.12位异或运算符

exclusive-or-expression:
    and-expression
    exclusive-or-expression ˆ and-expression
1 The usual arithmetic conversions are performed; the result is the bitwise
exclusive OR function of the operands. The operator applies only to integral
or unscoped enumeration operands.

c++ 11 5.13位包含或运算符

inclusive-or-expression:
    exclusive-or-expression
    inclusive-or-expression | exclusive-or-expression
1 The usual arithmetic conversions are performed; the result is the bitwise
inclusive OR function of its operands. The operator applies only to integral
or unscoped enumeration operands.

这些运算符的定义我完全想不起来了。在标准的其他地方吗?是否为有符号整数定义了结果实现?

作为一个例子,让我们看看下面的代码:

signed char a=-1;
signed char b=3;
signed char c=a&b;

对于2的补码,a为1111 1111,b为0000 0011。最后c等于0000 0011(+3)。

对于1的补码,a为1111 1110,b为0000 0011。c是否等于0000 0010 (+2)?

有符号大小,a为10000001,b为00000011。c是否等于00000001 (+1)?

如果您可以使用1的补码或符号大小访问平台,那么在这些平台上的结果是什么?

按位运算独立地对每个位进行操作,无论每个位作为数字类型的一部分解释时可能意味着什么。

所以是,10000001 & 00000011 == 00000001,不管每个位是代表一个符号还是值的一部分

按位& | ^运算符仅对两个操作数中的每个位进行命名运算,这将根据底层类型的表示而具体实现。

但是,对于移位,情况就不同了。

例如,考虑一个一个字节的双补-1 = 11111111。然后右移一个。现在是你的数字127(改变符号)或-1(将1移到最高位而不是0)。如果它是一个符号幅度表示,同样的事情也适用。为了避免所有这些问题,标准只是禁止它。

负号整数的左移和右移由标准按照它们的方式处理,以便允许实现使用"算术移位"机器指令。算术右移复制符号位,不像逻辑右移在左边插入0 s。在某些体系结构中,如果从左边缘移出的位与符号位不同,则算术左移可能会产生溢出异常。因此,右移是实现定义的(因为结果总是有效的,但可能因实现而异),而左移是未定义的(因为结果可能是中断)

按位逻辑运算符产生的位模式是完全指定的,但对于有符号整数,结果可能是一个陷阱值(例如-0在1补码或符号幅度架构中,-0无效)。在这种情况下,结果是未定义的行为,根据第5节介绍的第4段:

如果在表达式求值期间,结果没有在数学上定义,或者不在其类型的可表示值范围内,则行为未定义。

结果与机器如何表示整数无关。

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

上表显示了1位的值。给定一个32位整数,对所有32位进行位计算。