为什么 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 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 int
到int
的转换可能有效,也可能是未定义的行为,这取决于平台和值(唯一的保证是int
不大于long int
,但它们可能是相同的大小)。
换句话说,整数类型之间转换的问题是实现的偶然产物,而不是设计决策。警告它们更好,特别是如果可以在编译时检测到由于这些限制而无法工作。
还要注意,即使从double
到int
的转换也是合法且定义良好的(如果在边界内完成),并且即使在编译时可以看到精度损失,也不需要实现警告它。如果编译器在有意义的情况下发出过多警告,可能会造成问题(您只需禁用警告,或者更糟的是,养成了接受非干净构建的习惯)。
这些隐式转换规则可能会与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和LLVM提供了诸如Clang静态分析器, Klee项目和Clang对许多未定义行为的类生成警告(包括null的解引用,超大移位等)在代码中明显捕捉到一些常见的错误。
-fcatch-undefined-behavior
(现在的undefinedbehaviorsantizer - UBSan -)的工具来避免这些可能的错误。
通过在本文代码中运行UBSan, clang++
和以下参数-fsanitize=undefined
将捕获错误,如下所示:
runtime error: value 4.29497e+09 is outside the range of representable values of type 'int'
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 错误:隐式转换更改符号:'int'到'unsigned long'
- 对 '(const Y) (int&, std::mersenne_twister_engine<long unsigned int,
- 自动类型默认为 int 而不是 long
- 错误:'class std::unique_ptr<std::set<long unsigned int> >'没有名为 'size' 的成员
- "1L << count"是什么意思?如何使用超出"unsigned long long int? "范围的语句编号打印?
- Visual studio 2013 和 g++ 7.1 中将 int 和 long 类型相乘时的 c++ 差异行为
- 错误:调用'begin(long double [nPoints])'没有匹配函数;使用硬编码的 int 与整数变量初始化向量
- 只读位置'__result.std::_Rb_tree_const_iterator<_Tp>::operator*<long long int>()'分配错误
- C++ vector::size_type:有符号与无符号;int vs. long
- 错误:将"long int (*)[4]"分配给"long int [4][4]"时的类型不兼容
- 没有匹配函数来调用"std::basic_ofstream<char>::write(std::string*, long long unsigned int)"
- 函数参数可以是char*、long或int.可能吗
- unsigned int/signed int/long-long:无法解释的输出
- 如何在C++中将二进制文件上下文转换为 int/long 值
- <int> <long> 当它们的大小相同时,将矢量转换为矢量?
- " long unsigned typedef int long ullong; "是什么意思?
- 我如何使用3个重载函数(参数的差异是int, long, float)同时只要求一个输入项
- 使用非固定整数(int, long)而不是固定大小的整数(int64_t, int32_t)有什么优势吗?