我正在分析代码库中的一些警告,并对 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
查看在 godbolt 上的两个编译器上运行的程序。
强制转换不会在编译的代码中发生,val2
保留其原始值。计算结果是正确的。这个警告警告我的实际危险是什么?如何触发此行为?警告是假的吗?
第二次转换是事情变得依赖于实现的地方。
第一个(表达式val1+val2
的评估(触发val2
从有符号到无符号的转换,这是符合标准和记录的。因此,表达式的结果是无符号的。
第二个(将生成的未签名转换回已签名(是潜在问题随之而来的地方。如果无符号值不在目标有符号类型的定义域中(在本例中,它不在(,则会出现实现行为,您不能假设该行为在已知域中可移植。
这个警告警告我的实际危险是什么?
潜在的危险是您可能没有意识到隐式符号转换,并且是偶然进行的。如果它是故意的并且按照预期行事,那么就没有危险(。
如何触发此行为?
您已触发隐式符号转换。
也就是说,如果您想看到一些可能让您感到惊讶的输出,请尝试以下操作:
std::cout << val1 + val2;
警告是假的吗?
取决于你对假货的定义。
程序中肯定存在隐式符号转换,因此,如果您要求编译器警告隐式符号转换,那么编译器警告程序中的隐式符号转换是完全正确的。
默认情况下不启用此警告选项,在使用 -Wall 启用"所有"警告时,甚至在使用 -Wextra 启用"额外"警告时,都是有原因的。这些符号转换警告具有明确定义行为的程序,但对于没有密切关注的人来说,这可能会令人惊讶。尽管有此警告,程序也可能有意义且正确。