C 中文字和 return 值类型转换的奇怪结果
Weird results with type conversion of literals and return values in C
关于这个简单代码的两个问题:
float foo(){
return 128.0;
}
int main(){
char x = (char) 128;
char y = (char) 128.0;
char z = (char) foo();
printf("x: %d \ny: %d \nz: %d", x, y, z);
}
我的输出:
x: -128
y: 127
z:-128
为什么 128.0 在转换为 char
时不会溢出,为什么 不是 它是函数的 return 值而不是比文字?如果需要足够的答案,我很乐意真正深入细节:)
(我使用的是 gcc-4.8.1,没有使用任何编译选项,只是 gcc file.c)
y
的结果是未定义的行为
如您所见,不同的编译器给出不同的结果。
z
也是一个未定义的行为,但没有启用优化,即使这个非常微不足道的例子也被评估了。但是,如果启用优化,结果将相同(因为编译器会选择结果)。
您的 C 实现似乎具有带符号的八位 char
类型。 128 不能用这种类型表示。
在char x = (char) 128;
中,有一个从int
值128到char
类型的转换。对于这个整数到整数的转换,C 2018 6.3.1.3 3 说:
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.
“实现定义”意味着需要一个符合标准的 C 实现来记录它在此转换中的行为方式,并且必须遵守该实现。您的实现显然包含模 256,结果是将 128 转换为 char
产生 −128.
在char y = (char) 128.0;
中,有一个从double
值128到char
类型的转换。对于这个浮点数到整数的转换,C 2018 6.3.1.4 2 说:
If the value being converted is outside the range of values that can be represented, the behavior is undefined.
“未定义”表示C标准没有强加任何要求; C 实现不必记录其行为,也不必遵守任何特定规则。特别是,行为在不同情况下可能会有所不同。
我们看到 char y = (char) 128.0;
和 char z = (char) foo();
产生了不同的结果(127 和 −128)。一个常见的原因是,由于使用了常量,编译器可能已经使用内部软件评估了 (char) 128.0
本身,该软件将超出范围的结果限制在类型的限制内,因此超出范围128 导致最大可能的 127,并且 y
被初始化为那个。另一方面,对于 char () foo()
,编译器可能已经生成了在 运行 时执行转换的指令,这些指令的行为不同于内部编译器评估和包装模 256,产生 −128。
由于 C 标准或您的编译器文档未指定这些行为,因此您不应依赖它们。
关于这个简单代码的两个问题:
float foo(){
return 128.0;
}
int main(){
char x = (char) 128;
char y = (char) 128.0;
char z = (char) foo();
printf("x: %d \ny: %d \nz: %d", x, y, z);
}
我的输出:
x: -128
y: 127
z:-128
为什么 128.0 在转换为 char
时不会溢出,为什么 不是 它是函数的 return 值而不是比文字?如果需要足够的答案,我很乐意真正深入细节:)
(我使用的是 gcc-4.8.1,没有使用任何编译选项,只是 gcc file.c)
y
的结果是未定义的行为
z
也是一个未定义的行为,但没有启用优化,即使这个非常微不足道的例子也被评估了。但是,如果启用优化,结果将相同(因为编译器会选择结果)。
您的 C 实现似乎具有带符号的八位 char
类型。 128 不能用这种类型表示。
在char x = (char) 128;
中,有一个从int
值128到char
类型的转换。对于这个整数到整数的转换,C 2018 6.3.1.3 3 说:
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.
“实现定义”意味着需要一个符合标准的 C 实现来记录它在此转换中的行为方式,并且必须遵守该实现。您的实现显然包含模 256,结果是将 128 转换为 char
产生 −128.
在char y = (char) 128.0;
中,有一个从double
值128到char
类型的转换。对于这个浮点数到整数的转换,C 2018 6.3.1.4 2 说:
If the value being converted is outside the range of values that can be represented, the behavior is undefined.
“未定义”表示C标准没有强加任何要求; C 实现不必记录其行为,也不必遵守任何特定规则。特别是,行为在不同情况下可能会有所不同。
我们看到 char y = (char) 128.0;
和 char z = (char) foo();
产生了不同的结果(127 和 −128)。一个常见的原因是,由于使用了常量,编译器可能已经使用内部软件评估了 (char) 128.0
本身,该软件将超出范围的结果限制在类型的限制内,因此超出范围128 导致最大可能的 127,并且 y
被初始化为那个。另一方面,对于 char () foo()
,编译器可能已经生成了在 运行 时执行转换的指令,这些指令的行为不同于内部编译器评估和包装模 256,产生 −128。
由于 C 标准或您的编译器文档未指定这些行为,因此您不应依赖它们。