为啥在 gcc 和 clang 上通过优化将大 double 转换为 uint16_t 会给出不同的答案

Posted

技术标签:

【中文标题】为啥在 gcc 和 clang 上通过优化将大 double 转换为 uint16_t 会给出不同的答案【英文标题】:Why does converting an large double to a uint16_t with optimizations on gcc and clang give different answers为什么在 gcc 和 clang 上通过优化将大 double 转换为 uint16_t 会给出不同的答案 【发布时间】:2018-12-01 11:49:04 【问题描述】:

开启优化后,下面的代码会在 gcc 上产生不同的结果。如果没有优化,gcc 会产生与 clang 相同的结果。

#include <cfloat>
#include <cstdint>

double big_dbl()  return DBL_MAX; 

int main() 
    return static_cast<std::uint16_t>(big_dbl());

-O0 的汇编器输出显示 gcc 和 clang 都调用 empty_dbl 并使用 cvttsd2si 进行浮点转换->int 转换,然后转换为 16 位无符号值并生成 0 .将优化级别提高到 -01 可以优化两个编译器中的 empty_dbl 调用,但 clang 仍然给出 0 作为强制转换的结果,而 gcc 给出 65535。可以使用 compiler explorer 看到结果。

这是 gcc 优化器中的错误还是未定义的行为,因此优化器可以做它喜欢的事情?

这最近困扰着我们,从某种意义上说,谢天谢地,因为它显示了 big_dbl 使用不正确的情况,我们已经正确修复了代码,但我想了解与 gcc 的区别。

【问题讨论】:

相关:***.com/questions/526070/… 【参考方案1】:

Quote 来自当前标准草案:

浮点类型的纯右值可以转换为整数类型的纯右值。转换截断;也就是说,小数部分被丢弃。 如果截断的值不能在目标类型中表示,则行为未定义。

所以实现可以为您的情况做任何他们喜欢的事情,因为行为是未定义的。

【讨论】:

以上是关于为啥在 gcc 和 clang 上通过优化将大 double 转换为 uint16_t 会给出不同的答案的主要内容,如果未能解决你的问题,请参考以下文章

为啥 clang 和 gcc 在这个虚拟继承代码上存在分歧?

为啥检查没有被优化

为啥在编译期间不使用 GCC 选项 -Os?

为啥 gcc 会产生这个奇怪的程序集 vs clang?

为啥 clang 无法展开循环(即 gcc 展开)?

为啥“#define WC(p) L#p”在 GCC 和 Clang 中不起作用?