获取从无符号到有符号的隐式转换溢出警告

Getting warnings for implicit conversion overflow from unsigned to signed

考虑以下有问题的代码:

#include <iostream>

void foo(int64_t y) {
    std::cout << y << "\n";
}

int main() {
    uint64_t x = 14400000000000000000ull;
    foo(x);
}

通常打印 -4046744073709551616.

如何让编译器帮助解决此类 conversion/overflow 问题?我尝试了以下方法:

g++ -g overflow.cpp -fsanitize=undefined -Wall -Wextra -pedantic -Wconversion -Wconversion
clang++ -g overflow.cpp -fsanitize=undefined,integer,implicit-conversion -Wall -Wextra -pedantic

None 其中给出任何编译时或 运行 时警告。

(clang 版本 7.0.0, gcc 版本 8.2.1)

GCC 和 Clang 都有警告选项 -Wsign-conversion 以在这种情况下发出警告。

warning: implicit conversion changes signedness: 'uint64_t' (aka 'unsigned long') to 'int64_t' (aka 'long') [-Wsign-conversion]

注意 GCC 关于 -Wconversion 的文档

... Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.

另请注意,该程序格式正确(因此必须成功编译)并且没有未定义的行为(因此没有理由触发消毒程序)。将不可表示的数字转换为有符号的结果在实现定义的值中。

这里的问题是 -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

这将警告您符号不匹配。