考虑以下有问题的代码:
#include <iostream>
void foo(int64_t y) {
std::cout << y << "\n";
}
int main() {
uint64_t x = 14400000000000000000ull;
foo(x);
}
通常打印-4046744073709551616
。
如何让编译器帮助解决这种类型的转换/溢出问题?我尝试了以下方法:
g++ -g overflow.cpp -fsanitize=undefined -Wall -Wextra -pedantic -Wconversion -Wconversion
clang++ -g overflow.cpp -fsanitize=undefined,integer,implicit-conversion -Wall -Wextra -pedantic
没有一个会给出任何编译或运行时警告。
(clang版本7.0.0,gcc版本8.2.1)
答案 0 :(得分:2)
这里的问题是-Wconversion
仅在值返回给源类型时可能不是同一类型时才会发出警告。例如,如果foo
取int
,则-Wconversion
将发出警告,因为您可能无法将int
中的值转换回原始uint64_t
值。如果有
uint64_t u = some_value;
int64_t s = static_cast<int64_t>(u);
uint64_t check = static_cast<uint64_t>(s)
然后check == u
将始终为真(只要int64_t
也是两个的称赞),因此-Wconversion
将不会发出警告,因为我们将源值取回了。
在这种情况下,您需要的是
-Wsign-conversion
这会警告您信号不匹配。
答案 1 :(得分:1)
GCC和Clang都有警告选项-Wsign-conversion在这种情况下发出警告。
警告:隐式转换将签名:'uint64_t'(又名“ unsigned long”)更改为“ int64_t”(又名“ long”)[-Wsign-conversion]
注意GCC关于-Wconversion的文档
...默认情况下,除非显式启用-Wsign-conversion,否则在C ++中默认禁用有关有符号和无符号整数之间转换的警告。
还请注意,程序格式正确(因此必须成功编译),并且没有未定义的行为(因此也没有理由触发清理程序)。将无法代表的数字转换为带符号的结果会导致实现定义值。