为什么 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?

本文关键字:int long 这样做 警告 clang double 为什么 转换      更新时间:2023-10-16

在以下代码中:

#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 version是3.6.2-svn240577-1~exp1

注2:我已经测试了它与许多其他版本的gcc, clang和icc感谢编译器资源管理器(gcc.godbolt.org)。因此,所有测试过的gcc版本(5.x除外)和icc都会抛出警告。

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++中使用太多逻辑。

通过阅读LLVM项目博客上由Chris Lattner (LLVM的主要作者)撰写的这篇很棒的文章《每个C程序员应该知道的关于未定义行为的事情》,特别是第3/3部分,我可以更好地理解Clang处理未定义行为的方法

因此,为了保证您对优化和时间经济的强烈诉求-"终极性能"-

请记住,编译器受限于没有动态信息和被限制在不烧掉很多东西的情况下

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

Clang对许多未定义行为的类生成警告(包括null的解引用,超大移位等)在代码中明显捕捉到一些常见的错误。

与此相反,Clang和LLVM提供了诸如Clang静态分析器Klee项目-fcatch-undefined-behavior(现在的undefinedbehaviorsantizer - UBSan -)的工具来避免这些可能的错误。

通过在本文代码中运行UBSanclang++和以下参数-fsanitize=undefined将捕获错误,如下所示:

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

相关文章: