C: 如果 x 是 char 类型,在 x=~x 中会发生什么(详细)?

C: What happens (in detail) in x=~x if x is of type char?

如果我们有如下代码:

char x = -1;
x =~x;

在带有 MS VS 编译器(部分支持 C99)的 x86 平台上 - 运行 时会发生什么?

据我所知,发生了以下情况(如有错误请指正):

实际发生的事情太多了——我觉得这有点令人困惑。特别是:我对最后一次隐式转换(从 int 到 char)的理解是否正确?如果赋值的结果不能存储在一个字符中会发生什么?

确实~xint类型。

如果 charunsigned,则返回 char 的转换是明确定义的。也是定义好的,当然,如果数值在char.

支持的范围内

如果 charsigned,则 ~xchar 的转换是实现定义的,有可能引发实现​​定义的信号。

在您的例子中,您有一个带有 2 的补码 int 和 2 的补码 char 的平台,因此 ~x 被观察为 0。

请注意,MSVC 并不完全支持任何 C 标准,它也没有声称支持。

您几乎是正确的,但错过了 char 具有实现定义的签名。它可以是有符号的或无符号的,具体取决于编译器。

在任何一种情况下,8 位 2 的补码字符的位模式确实是 0xFF,无论其符号如何。但是如果 char 被签名,整数提升将保留符号并且你仍然有值 -1,在 32 位计算机上的二进制 0xFFFFFFFF。但是,如果 char 是无符号的,则 -1 会在赋值时转换为 255,并且整数提升会给出 255 (0x000000FF)。所以你会得到不同的结果。

关于~的整数提升,它右边只有一个运算符,提升了那个。

最后,您将结果分配回 char,结果将再次取决于签名。从 intchar 赋值时,您将有一个隐式的 "lvalue conversion"。结果是实现定义的——很可能你得到了 int.

的最低有效字节

由此我们可以了解到:

  • 切勿使用 char 来存储整数值或算术。仅用于存储字符。相反,使用 uint8_t.
  • 切勿对可能已签名或通过隐式提升静默签名的操作数执行按位算术。
  • 除非操作数是 unsigned int 或更大的无符号类型,否则 ~ 运算符特别危险。

To my knowledge, the following happens (please correct me if I am wrong):

x is assigned the value -1, which is represented by the bit pattern 0xff since a char is represented by one byte.

1 是类型 int 整数常量 - 将其取反为 -1 并保持为 int。 -1 分配给 char x 。如果 char 符号 ,则 x 的值为 -1。如果 charunsignedx 将取 CHAR_MAX 的值,也就是 UCHAR_MAX。 “位模式 0xff”与此处无关。

The ~ operator promotes x to an int, that is, it internally works with the bit pattern 0xffffffff.

x 被提升为 int(或 unsignedCHAR_MAX == UINT_MAX 的稀有机器上 - 我们将忽略它)。 int 至少是 16 位。 -1 的值,当编码为绝大多数常见的 2 的补码时,是一个全 1 位模式。 (其他编码可能 - 我们也会忽略它)。如果 x 的值为 UCHAR_MAX,则 x 将具有位模式 00...00 1111 1111 - 假设为 8 位 char。其他可能的宽度 - 我们将忽略的另一件事。

The ~ operator's result is 0x00000000 (of type int).

是,(除非 CHAR_MAX == UINT_MAX,在这种情况下它是 unsigned 和值 11...11 0000 0000)。

To perform the assignment, the integer promotions apply (principally). Since in our case the operand on the right hand side is an int, no conversion occurs. The operand on the left hand side is converted to int. The assignment's result is 0x00000000.

由于分配,此处没有整数提升。由于 ~,促销已经发生。将发生类型更改,将 int 分配给 char。那不是升职。结果的类型为 char。作为缩小的一部分,0 的值不会出现范围问题,并导致值 0 和类型 char。 11...11 0000 0000 的值将通过实现定义的行为并可能导致值 0 并且肯定会键入 char.

如果代码是 (x =~x) + 0,那么 char (x =~x) 会在添加之前提升为 int

As a side effect, the left hand side of the assignment is assigned the value 0x00000000. Since x is of type char, there is another implicit conversion, which converts 0x00000000 to 0x00.

在前面提到。

What would happen if the assignment's result could not be stored in a char?

保存哪个值是实现定义的行为。它可能包括(很少)引发异常。


位屏蔽和操作最好使用无符号类型和数学来处理。