【问题标题】:Why does arithmetic operations on (more than) three unsigned chars always trigger a warning when using -Wconversion?为什么在使用 -Wconversion 时对(超过)三个无符号字符的算术运算总是触发警告?
【发布时间】:2021-11-06 09:51:24
【问题描述】:

编译如下代码

// foo.c

typedef unsigned char uint8_t;

int main() {
    uint8_t a = 1;
    uint8_t b = 10;
    uint8_t c = 12;

    uint8_t k = a + b + c;
}

通过以下完整命令使用 GCC 11.2(以及其他 GCC 版本):

gcc -Wconversion foo.c

导致以下警告:


Output of x86-64 gcc 11.2 (Compiler #3)
<source>: In function 'main':
<source>:11:17: warning: conversion from 'int' to 'uint8_t' {aka 'unsigned char'} may change value [-Wconversion]
   11 |     uint8_t k = a + b + c;
      |                 ^
Compiler returned: 0

例如,添加两个无符号字符(即a + b)时不会发生这种情况。 在超过三个无符号字符之间使用算术运算的任意组合时会发生这种情况。 并且在 clang 版本 12.0.1 中不会发生这种情况。

为什么a + b + c 会导致int 在分配给k 之前必须转换为uint8_t 以抑制警告?

【问题讨论】:

  • 或许有帮助:Implicit conversions
  • 猜测:对于三个项,a + b 的结果类型为int,因此第二个+int + uint8_t 形式的表达式。也许编译器总是警告int + uint8_t,但从不警告uint8_t + uint8_t
  • FWIW,gcc bugzilla 发现了 90 多个提到 -Wconversion 的活动错误。警告购买者。
  • Tortellini Teusday,可以使用 uint8_t k = ( uint8_t) (a + b + c); 来消除此类警告。
  • @chux-ReinstateMonica 是的,我知道这是一种方法,这在问题的最后一句话中有所说明。问题更多是关于为什么这会触发警告而a+b 例如不会

标签: c gcc gcc-warning


【解决方案1】:

这是由于整数提升在 C 中的工作方式。C 标准规定,如果 int 可以保存 ab 类型的值 - 那么它们将转换为 int操作。

uint8_tint 就是这种情况。

引用标准(6.3.1.1):

每个整数类型都有一个整数转换等级定义如下

...

如果一个 int 可以表示原始类型的所有值,则该值为 转换为 int;否则,它将转换为无符号整数。 这些被称为整数促销。 48) 所有其他类型都是 整数促销保持不变


在旧版本的 gcc 中 - 此警告由添加两个操作数(如 a + b)触发的。在 GCC 10 中,默认情况下这已从 -Wconversion 中删除,但此警告适用于 -Warth-conversion。来自GCC 10 release notes

-Warith-conversion 重新启用来自 -Wconversion、-Wfloat-conversion 和 -Wsign-conversion 的警告,对于算术运算结果不会出现的表达式,这些警告现在默认关闭 由于提升而适合目标类型,但 表达式确实适合目标类型。

即由于 GCC 10,a + b 不会触发 -Wconversion 警告的原因是 express 的两个操作数都是 uint8_t,它们确实适合目标类型 (int)。

a + b + c 不再是这种情况,因为a + b 变成了int,而表达式变成了int + uint8_t - 这似乎不满足“表达式的操作数确实适合目标类型”。

【讨论】:

  • 如果您只添加两个,较新的 gcc 版本(10 及更高版本)不会发出警告。
  • 您的 gcc 版本似乎比 OP 的版本旧。我只收到版本 10 之前的 GCC 警告,但没有收到更高版本的警告。 godbolt.org/z/8P4aTdx9T
  • 随着 GCC 10 的发布,这种行为似乎确实发生了变化,我已经修复了答案。
  • Re “C 标准规定,如果 int 可以保存 ab 中的值 - 那么它们将转换为 int 以进行操作”:@中的值987654344@ 和 b 无关紧要。规则是,如果int 可以表示a 的类型可以表示的所有值,则将其转换为int,对于b 也是如此。例如,如果我们有 int128_t a = 1;uint128_t b = 3;,那么您的规则表达式将分别将 ab 转换为 int,因为 int 可以表示 1 和 3。但它们是不是(当 int 只有 32 位时)。
  • @EricPostpischil 我的意思是 ab 的类型,但你说得对,这不是 100% 清楚,我会解决这个问题
猜你喜欢
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 2016-05-06
  • 2019-11-17
  • 2023-03-18
  • 2022-08-12
  • 2014-05-19
相关资源
最近更新 更多