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 平台上 - 运行 时会发生什么?
据我所知,发生了以下情况(如有错误请指正):
- x 被赋予值 -1,它由位模式 0xff 表示,因为 char 由一个字节表示。
- ~ 运算符将 x 提升为 int,也就是说,它在内部使用位模式 0xffffffff。
- ~ 运算符的结果是 0x00000000(int 类型)。
- 要执行分配,整数提升适用(主要)。由于在我们的例子中右侧的操作数是一个 int,因此不会发生转换。左侧的操作数被转换为 int。赋值结果为 0x00000000.
- 作为副作用,分配的左侧被分配了值 0x00000000。由于x是char类型,所以还有一个隐式转换,将0x00000000转换为0x00。
实际发生的事情太多了——我觉得这有点令人困惑。特别是:我对最后一次隐式转换(从 int 到 char)的理解是否正确?如果赋值的结果不能存储在一个字符中会发生什么?
确实~x
是int
类型。
如果 char
是 unsigned
,则返回 char
的转换是明确定义的。也是定义好的,当然,如果数值在char
.
支持的范围内
如果 char
是 signed
,则 ~x
到 char
的转换是实现定义的,有可能引发实现定义的信号。
在您的例子中,您有一个带有 2 的补码 int
和 2 的补码 char
的平台,因此 ~x
被观察为 0。
请注意,MSVC 并不完全支持任何 C 标准,它也没有声称支持。
您几乎是正确的,但错过了 char
具有实现定义的签名。它可以是有符号的或无符号的,具体取决于编译器。
在任何一种情况下,8 位 2 的补码字符的位模式确实是 0xFF,无论其符号如何。但是如果 char
被签名,整数提升将保留符号并且你仍然有值 -1
,在 32 位计算机上的二进制 0xFFFFFFFF。但是,如果 char
是无符号的,则 -1
会在赋值时转换为 255
,并且整数提升会给出 255
(0x000000FF
)。所以你会得到不同的结果。
关于~
的整数提升,它右边只有一个运算符,提升了那个。
最后,您将结果分配回 char
,结果将再次取决于签名。从 int
到 char
赋值时,您将有一个隐式的 "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。如果 char
是 unsigned,x
将取 CHAR_MAX
的值,也就是 UCHAR_MAX
。 “位模式 0xff”与此处无关。
The ~ operator promotes x to an int, that is, it internally works with the bit pattern 0xffffffff.
x
被提升为 int
(或 unsigned
在 CHAR_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?
保存哪个值是实现定义的行为。它可能包括(很少)引发异常。
位屏蔽和操作最好使用无符号类型和数学来处理。
如果我们有如下代码:
char x = -1;
x =~x;
在带有 MS VS 编译器(部分支持 C99)的 x86 平台上 - 运行 时会发生什么?
据我所知,发生了以下情况(如有错误请指正):
- x 被赋予值 -1,它由位模式 0xff 表示,因为 char 由一个字节表示。
- ~ 运算符将 x 提升为 int,也就是说,它在内部使用位模式 0xffffffff。
- ~ 运算符的结果是 0x00000000(int 类型)。
- 要执行分配,整数提升适用(主要)。由于在我们的例子中右侧的操作数是一个 int,因此不会发生转换。左侧的操作数被转换为 int。赋值结果为 0x00000000.
- 作为副作用,分配的左侧被分配了值 0x00000000。由于x是char类型,所以还有一个隐式转换,将0x00000000转换为0x00。
实际发生的事情太多了——我觉得这有点令人困惑。特别是:我对最后一次隐式转换(从 int 到 char)的理解是否正确?如果赋值的结果不能存储在一个字符中会发生什么?
确实~x
是int
类型。
如果 char
是 unsigned
,则返回 char
的转换是明确定义的。也是定义好的,当然,如果数值在char
.
如果 char
是 signed
,则 ~x
到 char
的转换是实现定义的,有可能引发实现定义的信号。
在您的例子中,您有一个带有 2 的补码 int
和 2 的补码 char
的平台,因此 ~x
被观察为 0。
请注意,MSVC 并不完全支持任何 C 标准,它也没有声称支持。
您几乎是正确的,但错过了 char
具有实现定义的签名。它可以是有符号的或无符号的,具体取决于编译器。
在任何一种情况下,8 位 2 的补码字符的位模式确实是 0xFF,无论其符号如何。但是如果 char
被签名,整数提升将保留符号并且你仍然有值 -1
,在 32 位计算机上的二进制 0xFFFFFFFF。但是,如果 char
是无符号的,则 -1
会在赋值时转换为 255
,并且整数提升会给出 255
(0x000000FF
)。所以你会得到不同的结果。
关于~
的整数提升,它右边只有一个运算符,提升了那个。
最后,您将结果分配回 char
,结果将再次取决于签名。从 int
到 char
赋值时,您将有一个隐式的 "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。如果 char
是 unsigned,x
将取 CHAR_MAX
的值,也就是 UCHAR_MAX
。 “位模式 0xff”与此处无关。
The ~ operator promotes x to an int, that is, it internally works with the bit pattern 0xffffffff.
x
被提升为 int
(或 unsigned
在 CHAR_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?
保存哪个值是实现定义的行为。它可能包括(很少)引发异常。
位屏蔽和操作最好使用无符号类型和数学来处理。