问题描述
在下面的示例中,“a + b”将溢出两个变量的大小。这个临时结果会存储在 16 位空间还是需要的最大空间?
这种情况是否跨编译器标准化? 系统架构重要吗?我在 8 位微控制器上。 Short 类型为 16 位。
res 是否等于 50000、17232 或未定义?
unsigned short a = 50000;
unsigned short b = 50000;
unsigned short res = 0;
void main()
{
res = (a + b) / 2;
}
解决方法
严格来说,无符号类型不会溢出而是“环绕”,这是定义明确的行为,但可能出乎意料。正式参见例如 C 标准 C17 6.2.4/9:
涉及无符号操作数的计算永远不会溢出, 因为无法由结果无符号整数类型表示的结果是 以比可以得到的最大值大 1 的数为模减少 由结果类型表示。
为了完全理解这些内容,您需要从 Implicit type promotion rules 开始。许多 C 表达式中都有各种隐含和微妙的东西。
在这种特殊情况下,不可能有任何隐式转换,因为 unsigned short
在任何已知的 8 位系统上都是 16 位,int
也是如此。在这种情况下,unsigned short
只是转换为 unsigned int
,两者都是 16 位。
由于它是一个无符号类型,C 标准保证环绕并产生值 34464,这意味着最终结果保证在所有 8- 和 16- 上变为 17232现实世界中的位系统。如果类型已签名,则不会有任何保证,但会因为溢出而出现未定义的行为。
总结:
这个临时结果会存储在 16 位空间还是需要的最大空间?
16 位空间,因为只有(可能提升的)操作数的类型才重要。
这种情况是否跨编译器标准化?
是的,在无符号类型的情况下,代码在 8 位和 16 位系统上是 100% 可移植的。这是由 C 标准保证的。
系统架构重要吗?
是的,int
的大小在决定是否推广某物时很重要。在 8 位和 16 位苦味中,int
始终是事实上的 16 位(尽管理论上 C 允许它是其他东西)。在 32 位和 64 位苦味中,它实际上始终是 32 位。
res 是否等于 50000、17232 或未定义?
8 位和 16 位系统上为 17232,32 位和 64 位系统上为 50000。