为什么没有clang警告从double到int的隐式转换,但是从long到int时呢?

Vin*_* Sa 7 c++ gcc clang gcc-warning c++11

在以下代码中:

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

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

warning: implicit conversion from 'const long' to 'int' changes value from 4294967296 to 0 [-Wconstant-conversion]
Run Code Online (Sandbox Code Playgroud)

没关系.但是如果转换是从double到int,则没有警告,如下面的代码所示:

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

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

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

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

650*_*502 5

从整数类型的转换double“按设计”更改了值(认为3.141592654转换为int)。

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

换句话说,整数类型之间的转换问题是实现的偶然产物,而不是设计决策。对它们发出警告会更好,特别是如果可以在编译时检测到某些内容由于这些限制而无法工作。

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

这些隐式转换规则可能会与其他 C++ 问题相结合,变得真正奇怪且难以证明行为的合理性,例如:

std::string s;
s = 3.141592654; // No warnings, no errors (last time I checked)
Run Code Online (Sandbox Code Playgroud)

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


Vin*_* Sa 1

好吧,通过阅读LLVM 项目博客上这篇名为“每个 C 程序员应该了解的未定义行为”的精彩文章(特别是第 #3/3 部分),作者是 LLVM 的主要作者 Chris Lattner,我可以更好地理解Clang 的方法到处理未定义的行为。

所以,为了保证您对优化和时间经济的强烈诉求——“终极性能”——

但请记住,编译器因不具有动态信息而受到限制,并且在不消耗大量编译时间的情况下仅限于其所能提供的信息。

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

Clang 会针对许多类未定义行为(包括取消引用 null、过大的移位等)生成警告,这些警告在代码中很明显,以捕获一些常见错误。

相反,Clang 和 LLVM 提供了Clang Static Analyzer、Klee project和-fcatch-undefined-behavior(现在的UndefinedBehaviorSanitizer - UBSan - )等工具来避免这些可能的错误。

通过在所提供的代码中运行UBSanclang++ ,并使用以下参数,-fsanitize=undefined将捕获错误,如下所示:

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