将无符号值分配给带符号的字符
Assigning an unsigned value to a signed char
简单的C语言类型转换问题,假设这行代码:
signed char a = 133;
由于 signed char 的最大值是 128
,根据转换的第三条规则,上面的代码是否具有 implementation defined
行为?
if the value cannot be represented by the new type and it's not unsigned, then the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
这是赋值时的隐式类型转换。 133 将被一点一点地复制到变量 a
中。二进制中的 133 是 10000101
,当复制到 a
时将表示一个负数,因为如果前导位是 1 那么它表示一个负数。那么 a
的实际值将通过使用 2 的补码方法来确定,结果是 -123(这也取决于负数是如何为有符号数据类型实现的)。
首先,133不是无符号的。因为它总是适合 int
,所以它将是 int
类型,并且有符号(此外在 C99+ 中,所有无后缀的 decimal 常量都是有符号的!得到无符号数必须在末尾添加 U
/u
)。
其次,这不是转换而是转换。 C 中的强制转换是对特定类型的显式转换(或非转换),用构造 (type)expression
标记。在这种情况下,您可以编写初始化以使用带有
的显式转换
signed char a = (signed char)133;
在这种情况下,它不会改变初始化的行为。
第三,这确实是一个初始化,而不是赋值,所以它对于什么是可接受的表达式有不同的规则。如果此初始化程序用于具有静态存储持续时间的对象,则初始化程序必须是某种编译时常量。但是对于 this 特殊情况,赋值和初始化都会以相同的方式进行 conversion。
现在我们来看看 第三个整数转换规则是否适用 - 为此你需要知道前两个规则是什么:
目标类型是整数类型(不是 _Bool
),其中包含可表示的值(在这种情况下不适用,因为众所周知,如果 SCHAR_MAX
是 127)
目标类型是 unsigned(其实不是)
因此我们得到 C11 6.3.1.3p3:
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
问题是它是否具有实现定义的行为 - 是的,实现必须记录将要发生的事情 - 无论是如何计算结果,还是在那种情况下会发出哪个信号。
对于GCC 10.2 the manuals state it:
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
Clang 的“文档”“有点”不太容易访问,you just have to read the source code...
简单的C语言类型转换问题,假设这行代码:
signed char a = 133;
由于 signed char 的最大值是 128
,根据转换的第三条规则,上面的代码是否具有 implementation defined
行为?
if the value cannot be represented by the new type and it's not unsigned, then the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
这是赋值时的隐式类型转换。 133 将被一点一点地复制到变量 a
中。二进制中的 133 是 10000101
,当复制到 a
时将表示一个负数,因为如果前导位是 1 那么它表示一个负数。那么 a
的实际值将通过使用 2 的补码方法来确定,结果是 -123(这也取决于负数是如何为有符号数据类型实现的)。
首先,133不是无符号的。因为它总是适合 int
,所以它将是 int
类型,并且有符号(此外在 C99+ 中,所有无后缀的 decimal 常量都是有符号的!得到无符号数必须在末尾添加 U
/u
)。
其次,这不是转换而是转换。 C 中的强制转换是对特定类型的显式转换(或非转换),用构造 (type)expression
标记。在这种情况下,您可以编写初始化以使用带有
signed char a = (signed char)133;
在这种情况下,它不会改变初始化的行为。
第三,这确实是一个初始化,而不是赋值,所以它对于什么是可接受的表达式有不同的规则。如果此初始化程序用于具有静态存储持续时间的对象,则初始化程序必须是某种编译时常量。但是对于 this 特殊情况,赋值和初始化都会以相同的方式进行 conversion。
现在我们来看看 第三个整数转换规则是否适用 - 为此你需要知道前两个规则是什么:
目标类型是整数类型(不是
_Bool
),其中包含可表示的值(在这种情况下不适用,因为众所周知,如果SCHAR_MAX
是 127)目标类型是 unsigned(其实不是)
因此我们得到 C11 6.3.1.3p3:
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
问题是它是否具有实现定义的行为 - 是的,实现必须记录将要发生的事情 - 无论是如何计算结果,还是在那种情况下会发出哪个信号。
对于GCC 10.2 the manuals state it:
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
Clang 的“文档”“有点”不太容易访问,you just have to read the source code...