C 在方程式中溢出?

C overflows inside an equation?

a + b 如我所料将 255 溢出回 4,然后 c / 2 如我所料给出 2。但是为什么最后一个例子在计算相同的两个步骤时不会溢出?

我猜内部计算值存储了更多位,然后在进行赋值时才被截断为 8 位。那么极限在哪里,它一定会在某个时候溢出?

uint8_t a = 250;
uint8_t b = 10;
uint8_t c = (a + b);
uint8_t d = c / 2;
uint8_t e = (a + b) / 2;

std::cout << unsigned(c) << ", " << unsigned(d) << ", " << unsigned(e) << "\n";

4, 2, 130

a+b 给出的值 260 未分配给任何 uint8_t 类型,因此您在最后一种情况下很好。只有当您将任何大于 255 的值分配给 uint8_t 时才会发生溢出。

这叫做积分推广。这些操作本身是在您的 CPU 原生整数类型 int 中完成的,它可以容纳大于 255 的数字。在 a+b 的情况下,结果必须存储在 uint8_t 中,这就是截断完成。在最后一种情况下,首先有一个作为 int 完成的除法,结果可以完美地存储在 uint8_t.

下面的(a + b)不会溢出,编译器将ab识别为整数类型,所以加法结果是整数类型,这个表达式的结果不受限制根据表达式中项或因子的大小。

让我们假设变量的类型,如 ab 在这种情况下将结果限制为该类型。虽然可能,但几乎不可能使用这样的语言。想象一下五个变量,当不考虑类型时,它们总和为 500,即 this..

uint8_t a = 98;
uint8_t b = 99;
uint8_t c = 100;
uint8_t d = 101; 
uint8_t e = 102;

以上变量的总和== 500。现在...在下面任何表达式的结果都不能超过其中一项的大小...

int incorrect = (a + b + c + d + e);

在这种情况下 (a + b + c) == 41 然后 (41 + d + e) == 244。这是一个荒谬的答案。大多数人都认可的替代方案即

(98 + 99 + 100 + 101 + 102) == 500;

这是存在类型转换的原因之一。

表达式中的中间结果不应受表达式中的项或因子的限制,而应受结果类型(即左值)的限制。

@atturri 是正确的。这是 x86 机器语言中您的变量发生的情况:

REP STOS DWORD PTR ES:[EDI]
MOV BYTE PTR SS:[a],0FA
MOV BYTE PTR SS:[b],0A
MOVZX EAX,BYTE PTR SS:[a] ; promotion to 32bit integer
MOVZX ECX,BYTE PTR SS:[b] ; promotion to 32bit integer
ADD EAX,ECX
MOV BYTE PTR SS:[c],AL ; ; demotion to 8bit integer
MOVZX EAX,BYTE PTR SS:[c]
CDQ
SUB EAX,EDX
SAR EAX,1
MOV BYTE PTR SS:[d],AL
MOVZX EAX,BYTE PTR SS:[a]
MOVZX ECX,BYTE PTR SS:[b]
ADD EAX,ECX
CDQ
SUB EAX,EDX
SAR EAX,1
MOV BYTE PTR SS:[e],AL