C中的无符号溢出
考虑以下C代码:
#include uint32_t inc(uint16_t x) { return x+1; }
当使用gcc-4.4.3在纯x86_64系统上使用标志-std = c99 -march = core2 -msse4.1 -O2 -pipe -Wall进行编译时,它会生成
movzwl %di,%eax inc %eax retq
现在,在C中预测无符号溢出。我不太了解x86_64汇编,但据我所知,16位参数寄存器被移动到32位寄存器,该寄存器递增并返回。 我的问题是,如果x == UINT16_MAX怎么办。 会发生溢出,标准规定x + 1 == 0,对吗? 但是,如果%eax是一个32位寄存器,它现在包含UINT16_MAX + 1,这是不正确的。
这让我在这里连接一个问题:是否有一种可移植的方法来禁用C中的无符号溢出,这样编译器就可以假设存储在大寄存器中的小变量的高位始终为0(所以它不需要清除它们)? 如果不是(或者如果解决方案在语法上是令人讨厌的),至少在GCC中有没有办法做到这一点?
非常感谢您的宝贵时间。
不,C类型受默认促销限制。 假设uint16_t
转换级别低于int
,它将被提升为int
,并且将以int
forms执行添加,然后在返回时转换为uint32_t
。
至于你最后的相关问题,我并不完全遵循你想要的。
使用不使用编译器中介进行计算的编码样式,请注意( 1
)将具有int
数据类型。
uint32_t inc(uint16_t x) { uint16_t y = x + 1; return y; }
标准描述整数溢出的方式的一个特点是它允许编译器假设不会发生溢出。 在您显示的情况下,编译器不应该保留溢出的行为,因为毕竟,x + 1可能采用的值的范围(假设溢出不存在)适合返回类型。
对于你的第二个问题,在C中没有对无符号类型的溢出,适用的术语是包装。 根据定义,无符号类型以模2 ^宽度计算。 无论何时将更宽的无符号类型转换为更窄的类型,高位都将被丢弃。 所有C编译器都应该像这样实现它,没有什么可以担心的。
从本质上讲,无符号类型非常简单,只有签名类型才会出现令人讨厌的东西。