考虑以下有问题的代码:
#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(
这里的问题是,如果值在强制转换为源类型时可能不是同一类型,-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
这将警告您标志不匹配。
GCC和Clang都有警告选项-Wsign-convert,在这种情况下发出警告。
警告:隐式转换将符号:"uint64_t"(又名"无符号长整型"(更改为"int64_t"(又名"长"([-Wsign-conversion]
注意 GCC 关于 -Wconversion 的文档
。默认情况下,有关有符号整数和无符号整数之间转换的警告在 C++ 中处于禁用状态,除非显式启用了 -Wsign 转换。
另请注意,程序格式良好(因此必须成功编译(,并且没有未定义的行为(因此没有理由触发清理器(。将无法表示的数字转换为有符号的结果在实现定义的值中。