Clang 向我发出签名更改的警告,但代码仍会产生正确的输出

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

我正在分析代码库中的一些警告,对 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;
}

使用 -Wconversion

编译这段代码时,Clang 给出了以下警告
<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

在两个编译器 on godbolt 上查看程序 运行。

编译后的代码中不会发生强制转换,val2 保留其原始值。计算结果正确。此警告警告我注意的 实际 危险是什么?我怎样才能触发这种行为?警告是假的吗?

second 转换是实现依赖的地方。

第一个(表达式 val1+val2 的计算)触发从 val2 到无符号从有符号的转换,这是符合标准和记录的。因此表达式的结果是无符号的。

第二个(将生成的无符号 返回 转换为有符号)是潜在问题随之而来的地方。如果无符号值不在目标有符号类型的定义域内(在本例中,它不在),则会出现实现行为,您不能假设它在已知的宇宙中是可移植的。

What is the actual danger that this warning is warning me against?

潜在的危险是您可能没有意识到隐式符号转换,而无意中进行了转换。如果它是故意的并且表现得如所愿,那么就没有危险。

How can I trigger this behaviour?

您已经触发了隐式符号转换。

就是说,如果您想看到一些可能会让您感到惊讶的输出,请试试这个:

std::cout << val1 + val2;

Is the warning bogus?

取决于你对假冒的定义。

程序中肯定存在隐式符号转换,因此如果您要求编译器警告隐式符号转换,那么编译器警告程序中的隐式符号转换是完全正确的.

默认情况下不启用此警告选项是有原因的,在使用 -Wall 启用 "all" 警告时,甚至在使用 -Wextra 启用 "extra" 警告时也是如此。这些符号转换警告警告程序具有明确的行为,但对于没有密切注意的人来说可能会感到惊讶。尽管有此警告,程序仍然有意义且正确。