如果我在 C 中执行以下代码:
#include <stdint.h>
uint16_t a = 4000;
uint16_t b = 8000;
int32_t c = a - b;
printf("%d", c);
结果它正确打印了“-4000”。但是,我有点困惑:从另一个减去一个更大的无符号整数时不应该有算术溢出吗?这里有什么铸造规则?这个问题似乎有点无聊,所以任何参考都将不胜感激。
如果我在 C 中执行以下代码:
#include <stdint.h>
uint16_t a = 4000;
uint16_t b = 8000;
int32_t c = a - b;
printf("%d", c);
结果它正确打印了“-4000”。但是,我有点困惑:从另一个减去一个更大的无符号整数时不应该有算术溢出吗?这里有什么铸造规则?这个问题似乎有点无聊,所以任何参考都将不胜感激。
这个问题实际上有些复杂。算术表达式的操作数使用标准 (C89)的第 3.2.1.5 节中的特定规则进行转换。在您的情况下,答案取决于类型uint16_t
是什么。如果它小于int
,例如short int
,那么操作数将被转换为int
-4000,但在 16 位系统上,uint16_t
可能是unsigned int
并且不会自动转换为有符号类型。
简短的回答是,这些都是int
在减法过程中提升的。对于长答案,请查看C 标准的第 6.3.1.1 节,其中讨论了算术表达式中的整数提升。标准中的相关语言:
如果 an
int
可以表示原始类型的所有值,则将该值转换为int
; 否则,将其转换为unsigned int
. 这些被称为整数促销。整数提升不会改变所有其他类型。
细节也在那里,但它们变得非常讨厌。
int32_t
在减法期间,两个操作数都被提升。如果结果大于最大值,int32_t
您会看到溢出。
事实上,有一个溢出,但 C 没有告诉你。
当解释为有符号整数时,溢出留下的值恰好是 -4000。这在 2 的补码机器上按设计工作。
尝试将结果解释为无符号,您会注意到 (u1-u2) 在 u1 < u2 时计算为一些看似无关的数字。