【问题标题】:How are the results of intermediate steps in an arithmetic expression stored when all terms in the expression are uint8_t?当表达式中的所有项都是 uint8_t 时,如何存储算术表达式中中间步骤的结果?
【发布时间】:2025-11-23 22:15:01
【问题描述】:

代码:

int main(void) {
    uint8_t x = 3;
    uint8_t y = 4;
    uint8_t z = 5;

    uint8_t a = (x - y) / z;
    uint8_t b = x - y;
    printf("a is %d\n", a);
    printf("b is %d\n", b);
    return 0;
}

有以下输出:

a is 0
b is 255

我希望(3 - 4) / 5 会导致溢出,因为(3 - 4) 因为uint8_t 是255。当涉及无符号整数的中间步骤导致负数时,为什么它不会溢出?在下一步 / 5 发生之前,(3 - 4) 的结果以什么格式存储?

【问题讨论】:

  • %d 不是 uint8_t 的正确格式说明符。是的,算术运算是使用提升为int 的操作数执行的。所以(x-y) 实际上会计算为-1 并且类型为int
  • 您使用的是哪个编译器? gcc -Wall 作为输出 a is 0 b is 255。对于这些值,我也许可以拼凑出一个解释。
  • @EugeneSh。当您在 printf 中使用 uint8_t 时,它会升级为 int,因此 "%d" 应该是正确的说明符。
  • @mch 我不确定。我记得可变参数函数有一个特殊的提升规则
  • 其实这里是对 255 和 0 的解释:3-4 = -1,在补码 2 表示中是 255。如果你将 -1 除以某个东西,结果是浮点数,这意味着能够代表否定。如果将其除以大于 1 的值,则结果介于 0 和 -1 之间。如果您将其强制为整数,则会四舍五入为 0。

标签: c integer-overflow unsigned-integer


【解决方案1】:

可以使用一个更简单的示例来了解实际情况:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint8_t x = 3;
    uint8_t y = 4;

    int a = (x - y);
    printf("a is %d\n", a);    // a is -1
    return 0;
}

(现场示例:http://ideone.com/C3SlIn)

您所看到的是 整数提升 的结果,这些提升是在 通常的算术转换中对 - 的操作数执行的。1 (C99) 标准中整数提升定义的相关部分:

[6.3.1.1] 如果一个int可以表示原始类型的所有值,则将该值转换为一个int;否则,将其转换为unsigned int

int 确实可以表示uint8_t 的所有值,因此减法实际上等价于:

int a = (int)x - (int)y;

换句话说,没有溢出。


1。但是为了避免一个常见的混淆,这种行为固有- 的工作原理;这不是因为我们在这里分配了int

【讨论】:

    最近更新 更多