为什么 clang 不警告从 double 到 int 的隐式转换,而是在从 long 到 int 时警告?

Why doesn't clang warn about implicit conversion from double to int, but do it when from long to int?

在下面的代码中:

#include <iostream>
int main()
{
  const long l = 4294967296;
  int i = l;
  return i; //just to silence the compiler
}

编译器警告隐式转换(使用 -Wall 和 -std=c++14)如下:

warning: implicit conversion from 'const long' to 'int' changes value from 4294967296 to 0 [-Wconstant-conversion]

没关系。但是如果是从double转int就没有警告,如下代码:

#include <iostream>
int main()
{
  const double d = 4294967296.0;
  int i = d;
  return i; //just to silence the compiler
}

为什么编译器在这些情况下会有不同的反应?

注1:clang版本为3.6.2-svn240577-1~exp1

注 2:感谢 Compiler Explorer (gcc.godbolt.org),我已经用许多其他版本的 gcc、clang 和 icc 对其进行了测试。因此,所有经过测试的 gcc 版本(5.x 除外)和 icc 都发出了警告。没有 clang 版本做到了。

double到整数类型的转换改变了值"by design"(想想3.141592654转换成一个int)。

long intint 的转换可能或有效,也可能是未定义的行为,具体取决于平台和值(唯一的保证是 int 不是比 long int 大,但它们可能大小相同)。

换句话说,整数类型之间的转换问题是实现的附带问题,而不是设计决定。关于它们的警告更好,特别是如果可以检测到在编译时由于这些限制某些东西不起作用。

另请注意,即使从 doubleint 的转换也是合法且定义明确的(如果在边界内完成)并且 不需要 实现即使在编译时可以看到精度损失,也要警告它。即使使用可能有意义,编译器也会发出过多警告,这可能是一个问题(您只是禁用警告,或者更糟的是养成了正常接受非干净构建的习惯)。

这些隐式转换规则可能与其他 C++ 皱纹相加,变得非常奇怪且难以证明行为的合理性,例如:

std::string s;
s = 3.141592654; // No warnings, no errors (last time I checked)

不要尝试在 C++ 中使用过多的逻辑。阅读规范效果更好。

好吧,通过阅读这篇名为 "What Every C Programmer Should Know About Undefined Behavior" 的精彩文章,特别是第 3/3 部分,位于 LLVM Project Blog,由 LLVM 的主要作者 Chris Lattner 撰写 - 我可以更好地理解 Clang 处理未定义行为的方法.

所以,为了保证您对优化和时间经济的强烈诉求 - "ultimate performance" -

Keep in mind though that the compiler is limited by not having dynamic information and by being limited to what it can without burning lots of compile time.

Clang 默认不运行 所有相关的未定义行为检查,

Clang generates warnings for many classes of undefined behavior (including dereference of null, oversized shifts, etc) that are obvious in the code to catch some common mistakes.

取而代之的是,Clang 和 LLVM 提供了 Clang 静态分析器Klee 项目-fcatch-undefined-behavior(现在 UndefinedBehaviorSanitizer - UBSan - ) 以避免这些可能的错误。

通过 运行ning UBSan 在提供的代码中,clang++ 带有以下参数 -fsanitize=undefined 错误将被捕获如下:

runtime error: value 4.29497e+09 is outside the range of representable values of type 'int'