C/C++中的强制类型转换在函数和表达式中是否有所不同?

4
#include <stdio.h>

double metersToFeet(double meters)
{
    return meters / 0.3048;
}

int main()
{
    printf("%u\n", (unsigned char)(char)(45.72 / 0.3048));
    printf("%u\n", (unsigned char)(char)metersToFeet(45.72));
    return 0;
}

这个程序在GCC和Clang下均输出以下结果:
127
150

为什么我得到了两个不同的数字?


1
在第一种情况下,编译器预先计算了该值并决定结果(150)大于char类型所能容纳的范围,因此将其截断为127。在第二种情况下,该值未被预先计算,因此运行时会对错误的转换进行处理。 - Hot Licks
是的,这种行为被称为饱和,但并非必需或可依赖。依赖未定义的行为就像你过马路时戴上眼罩一样危险。 - autistic
@undefinedbehaviour,既然你有这样一个合适的用户名,为什么不利用它在这个上下文中提供的机会(比如以“别惹我”或类似的方式结束评论)?请记住,评论是要被人类阅读的,因此受到艺术表达的影响! - Christian Rau
假设我把我的用户名改成“急性淋巴细胞白血病”会怎样? - autistic
2个回答

8
实际答案(150)如果是有符号的,超出了char(在正常系统上)的范围。这种转换会引发未定义行为;编译器可以任意处理。
来自C99标准的6.3.1.4:

当实数类型的有限值被转换为除_Bool之外的整数类型时,小数部分将被舍去(即该值将朝向零截断)。如果整数部分的值不能由整数类型表示,则其行为未定义。


哪个编译器会在文字溢出时执行饱和,而在变量溢出时什么也不做呢?但好吧,未定义行为就是未定义行为。 - Christian Rau
@ChristianRau:后者需要运行时开销。 - Oliver Charlesworth
“后者”指的是“什么都不做”吗?好吧,如果使用SSE进行整个转换,那么这可能是正确的,因为其整数缩小转换本质上更加针对饱和度。 - Christian Rau
@ChristianRau:啊,抱歉,我是指在运行时进行饱和处理。 - Oliver Charlesworth

5

45.72 / 0.3048 等于 150

在你的平台上,char 类型显然是一个有符号的 8 位类型。对于该类型,150 超出了范围。这意味着行为未定义。其余内容如下。

例如,在 ideone.com 上的 GCC 中我得到了 127 127,而在 MSVC 中我得到了 150 150。你得到了 127 150,这很有趣,但并不意外。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接