在以下代码中:
test.bat
编译器警告隐式转换(使用-Wall和-std = c ++ 14)如下:
#include <iostream>
int main()
{
const long l = 4294967296;
int i = l;
return i; //just to silence the compiler
}
没关系。但是如果转换是从double到int,则没有警告,如下面的代码所示:
warning: implicit conversion from 'const long' to 'int' changes value from 4294967296 to 0 [-Wconstant-conversion]
为什么编译器在这些情况下会有不同的反应?
注1:clang版本为3.6.2-svn240577-1~exp1
注2:感谢Compiler Explorer(gcc.godbolt.org),我已经使用gcc,clang和icc的许多其他版本对其进行了测试。因此,所有测试版本的gcc(除了5.x)和icc都会发出警告。没有铿锵版本。
答案 0 :(得分:3)
从double
到整数类型的转换会改变值&#34;按设计&#34; (想想3.141592654
转换为int
)。
从long int
到int
的转换可能或可能有效或可能是未定义的行为,具体取决于平台和价值(唯一的保证是int
不大于一个long int
,但它们的大小可能相同。)
换句话说,整数类型之间转换中的问题是实现的偶然工件,而不是设计决策。关于它们的警告更好,特别是如果可以在编译时检测到由于这些限制而无法正常工作。
另请注意,即使从double
转换为int
也是合法且定义明确的(如果在边界内完成),并且实施不是必需来警告即使在编译时可以看到精度的损失。即使在使用可能有意义的情况下发出过多警告的编译器也可能是一个问题(你只是禁用警告,甚至更糟糕的是养成接受非正常构建的习惯)。
这些隐式转换规则可能与其他C ++皱纹相结合,变得真正奇怪且难以证明行为如下:
std::string s;
s = 3.141592654; // No warnings, no errors (last time I checked)
不要试图在C ++中使用过多的逻辑。阅读规范效果更好。
答案 1 :(得分:1)
好吧,通过阅读这篇名为“每个C程序员应该知道的未定义行为的内容”这篇伟大的文章,特别是第3/3部分,LLVM Project Blog,由LLVM的主要作者Chris Lattner撰写 - 我可以更好地理解 Clang处理未定义行为的方法。
因此,为了保证您对优化和时间经济的强烈吸引力 - “最终表现” -
请记住,编译器受限于没有动态 信息,并限制在不烧钱的情况下 编译时间。
默认情况下,Clang不会运行所有相关的未定义行为检查
Clang为许多类的未定义行为生成警告 (包括取消引用null,超大班次等) 在代码中明显地发现了一些常见的错误。
而不是这个,Clang和LLVM提供的工具包括 Clang Static Analyzer , Klee项目和-fcatch-undefined-behavior
(现在UndefinedBehaviorSanitizer - < strong> UBSan - )以避免这些可能的错误。
通过在显示的代码clang++
中使用以下参数-fsanitize=undefined
运行 UBSan ,可以捕获以下错误:
runtime error: value 4.29497e+09 is outside the range of representable values of type 'int'