我在分析一个代码库中的一些警告时,被Clang生成的这个警告弄得一头雾水。
考虑以下C++代码。
#include <iostream>
int main(int , char *[])
{
uint32_t val1 = 10;
int32_t val2 = -20;
int32_t result = val1 + val2;
std::cout << "Result is " << result << "\n";
return 0;
}
当我在编译这段代码时,Clang给了我以下警告 -Wconversion
<source>:9:25: warning: implicit conversion changes signedness:
'unsigned int' to 'int32_t' (aka 'int') [-Wsign-conversion]
int32_t result = val1 + val2;
~~~~~~ ~~~~~^~~~~~
<source>:9:27: warning: implicit conversion changes signedness:
'int32_t' (aka 'int') to 'unsigned int' [-Wsign-conversion]
int32_t result = val1 + val2;
~ ^~~~
2 warnings generated.
GCC也给我这个警告,但是我需要提供 -Wsign-conversion
来触发它。
警告说 val2
将被投向 unsigned int
因此会失去它的招牌。到目前为止,一切都很好。但我希望上面的代码能产生出 错 输出,令我惊讶的是,它的工作完全正常。
Result is -10
请看在两个编译器上运行的程序 在戈壁上.
在编译后的代码中不会发生这种情况,而且...。val2
保持其原始值。计算的结果是正确的。什么是 实际 这个警告所警告我的危险?我如何才能触发这种行为?这个警告是假的吗?
这个警告实际是在警告我什么危险呢?
潜在的危险是,你可能没有意识到隐式符号转换,而不小心做了这个转换。如果是故意的,并且行为如愿,那么就没有危险)。)
如何触发这种行为?
你已经触发了隐式符号转换。
也就是说,如果你想看到一些可能让你感到惊讶的输出,可以试试这个。
std::cout << val1 + val2;
这个警告是假的吗?
取决于你对虚假的定义。
程序中肯定存在隐式符号转换,因此如果你要求编译器对隐式符号转换进行警告,那么编译器对程序中存在的隐式符号转换进行警告是完全正确的。
为什么默认情况下不启用这个警告选项,在使用-Wall启用 "所有 "警告时也不启用,甚至在使用-Wextra启用 "额外 "警告时也不启用,这是有原因的。这些符号转换警告会警告一个有明确行为的程序,但对于没有密切注意的人来说,可能是令人惊讶的。尽管有这个警告,一个程序仍然可以是有意义的和正确的。
符号转换警告 第二 转换的地方,事情变得依赖于实现。
第一个(表达式的评估 val1+val2
)触发转换 val2
从 signed 到 unsigned,这是符合标准的,也是有文档可查的。因此,表达式的结果是无符号的。
第二种(将产生的unsigned 后面 到signed类型)是潜在问题的地方。如果无符号值不在目标符号类型的定义域内(在这种情况下,它不是),那么实现行为就会随之而来,你不能假定它在已知宇宙中是可移植的。