Clang 给了我符号更改的警告,但代码仍然产生正确的输出

Clang gives me a warning of signedness change, however the code still produces correct output

本文关键字:代码 输出 符号 警告 Clang      更新时间:2023-10-16

我正在分析代码库中的一些警告,并对 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 启用"额外"警告时,都是有原因的。这些符号转换警告具有明确定义行为的程序,但对于没有密切关注的人来说,这可能会令人惊讶。尽管有此警告,程序也可能有意义且正确。