考虑以下C代码:
#include <stdint.h>
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中是否有办法做到这一点?
非常感谢你的时间。
答案 0 :(得分:6)
不,C类型受默认促销限制。假设uint16_t
的转化次数低于int
,则会将其提升为int
,并且此添加将以int
执行,然后转换为uint32_t
什么时候回来。
至于你最后的相关问题,我并不完全遵循你的想法。
答案 1 :(得分:3)
使用不使用编译器中介进行计算的编码样式,请注意(1
)将具有数据类型int
。
uint32_t inc(uint16_t x) {
uint16_t y = x + 1;
return y;
}
答案 2 :(得分:0)
标准描述整数溢出的方式的一个特点是它允许编译器假设不会发生溢出。在你显示的情况下,编译器不应该保留溢出的行为,因为毕竟,x + 1可能采用的值的范围(假设溢出不存在)适合返回类型。
答案 3 :(得分:-1)
对于你的第二个问题,在C中没有对无符号类型的溢出,适用的术语是包装。根据定义,无符号类型以模2 ^宽度计算。无论何时将更宽的无符号类型转换为更窄的类型,高位都将被丢弃。所有的C编译器都应该像这样实现它,没有什么可以担心的。
本质上,无符号类型非常简单,只有签名类型才会出现令人讨厌的东西。