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 的结果是未定义的行为

https://godbolt.org/z/3x68ze

如您所见,不同的编译器给出不同的结果。

z 也是一个未定义的行为,但没有启用优化,即使这个非常微不足道的例子也被评估了。但是,如果启用优化,结果将相同(因为编译器会选择结果)。

https://godbolt.org/z/WaPE4r

您的 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 标准或您的编译器文档未指定这些行为,因此您不应依赖它们。