从无符号除法结果赋值时的符号转换警告

Warnings on sign conversion when assigning from the result of unsigned division

我用 -Wsign-conversion 编译了以下代码:

int main() 
{
  unsigned int a = 8;
  int b = a + 8u;  // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
  int c = a - 8u;  // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
  int d = a * 8u;  // warning: implicit conversion changes signedness: 'unsigned int' to 'int'
  int e = a / 8u;  // gcc warns, but no warning in clang
}

从无符号除法的结果赋值时,Clang 不会发出警告,但 gcc 会。

为什么在这个特殊情况下会有所不同?

Clang 只是有点聪明:无符号整数除以大于或等于 2 的无符号整数意味着无符号整数结果将始终适合有符号整数对应项(对应于除法表达式)。但是,如果您除以一个值为 1 的无符号整数,则结果不再保证适合对应的有符号整数,并且 Clang 确实 发出警告:

#include <cstdint>

int main()  {
  uint8_t a = 240;    // '240 / 1' will not fit in int8_t
  int8_t e = a / 2u;  // No warning in clang
  int8_t f = a / 1u;  // warning: implicit conversion changes signedness: 'unsigned int' to 'int8_t' (aka 'signed char') [-Wsign-conversion]
}

也有人认为 Clang 应该能够忽略乘以 0 的类似特殊情况的警告;但是 Clang 不会,而 GCC 会:

// Clang warns, no warning in GCC.
int8_t g = a * 0u;

在这种情况下,Clang 非常聪明,w.r.t。部门和 GCC w.r.t。乘法。


最后,请注意,Clang 在除法期间发出此警告的门控似乎仅在除以 1 时出现,因为如果除以 0u,您将不会得到相同的 -Wsign-conversion;可以说它已被更相关的(在这种情况下)覆盖 -Wdivision-by-zero 警告:

int8_t h = a / 0u;
warning: division by zero is undefined [-Wdivision-by-zero]