【问题标题】:Clang gives me a warning of signedness change, however the code still produces correct outputClang 给我一个符号变化的警告,但是代码仍然产生正确的输出
【发布时间】:2020-06-16 00:00:04
【问题描述】:

我正在分析代码库中的一些警告,但对 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,因此会失去它的标志。到现在为止还挺好。但是我期待上面的代码会产生 incorrect 输出,令我惊讶的是它工作得非常好。

Result is -10

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

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

【问题讨论】:

  • 如果您想象(例如)对数组访问进行边界检查,您需要非常小心有符号 无符号转换以避免安全漏洞。这(非常)远非假设。因此,明确说明此类转换可以说是一种很好的风格,即使结果是您在您遇到的每台机器上所期望的结果。

标签: c++ clang compiler-warnings implicit-conversion unsigned-integer


【解决方案1】:

second 转换是事情变得依赖于实现的地方。

第一个(表达式val1+val2 的评估)触发将val2 从有符号转换为无符号,这是符合标准并记录在案的。因此,表达式的结果是无符号的。

第二个(将生成的未签名 back 转换为已签名)是潜在问题接踵而至的地方。如果无符号值不在目标有符号类型的定义域内(在这种情况下,它不在),则实现行为随之而来,您不能假设它可以跨已知宇宙移植。

【讨论】:

  • 虽然值超出可表示范围的带符号整数的初始化在技术上是实现定义的,但int32_t 保证具有二进制补码表示,因此实际上只有一个值可以合理预期。使用int32_t 已经失去了对非二进制补码系统的可移植性。从 C++20 开始,保证这个结果没有例外。
【解决方案2】:

这个警告警告我的实际危险是什么?

潜在的危险是您可能没有意识到隐式符号转换,并且是偶然发生的。如果它是故意的并且按预期行事,那么就没有危险)。

如何触发此行为?

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

也就是说,如果您想看到一些可能让您感到惊讶的输出,请尝试以下操作:

std::cout << val1 + val2;

警告是假的吗?

取决于你对虚假的定义。

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

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

【讨论】:

  • 两个答案都很好,我都赞成。我选择了你的,因为你提供了触发不需要的行为的代码。
  • 我的解释是val2 的转换搞砸了值,但转换回result 解决了这个问题。所以它是偶然的。 godbolt.org/z/3DbYC4
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2021-03-31
  • 2017-10-28
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多