在stdint.h中定义的C99签名整数类型是否在溢出的情况下表现出良好定义的行为?

对于C(short,int,long等)中的“标准”有符号整数类型的所有操作,如果它们产生超出[TYPE_MIN,TYPE_MAX]间隔的结果(其中TYPE_MIN,TYPE_MAX是最小值和最大整数值),则表现出未定义的行为可以通过特定整数类型存储的。

但是,根据C99标准,所有intN_t类型都需要具有二进制补码表示:

7.8.11.1精确宽度整数类型
1. typedef名称intN_t指定有符号整数类型,其宽度为N,没有填充位和二进制补码表示。 因此,int8_t表示宽度恰好为8位的有符号整数类型。

这是否意味着C99中的intN_t类型在整数溢出的情况下表现出良好定义的行为? 例如,这段代码定义明确吗?

 #include  #include  #include  int main(void) { printf("Minimum 32-bit representable number: %" PRId32 "\n", INT32_MAX + 1); return 0; } 

不,它没有。

对类型范围内的值的二进制补码表示的要求并不意味着溢出行为的任何内容。

中的类型只是现有类型的typedef(别名)。 添加typedef不会更改类型的行为。

C标准第6.5节第5段(C99和C11)仍然适用:

如果在计算表达式期间发生exception情况 (即,如果结果未在数学上定义或未在其类型的可表示值范围内),则行为未定义。

这不会影响无符号类型,因为无符号运算不会溢出; 它们被定义为产生包装结果,减少模数TYPE _MAX + 1.除了比int更窄的无符号类型被提升为(signed) int ,因此可能遇到相同的问题。 例如,这个:

 unsigned short x = USHRT_MAX; unsigned short y = USHRT_MAX; unsigned short z = x * y; 

如果shortint窄,则会导致未定义的行为。 (如果shortint分别为16和32位,则65535 * 65535产生4294836225 ,超过INT_MAX 。)

虽然将超出范围的值存储存储在存储器中的有符号类型通常会存储值的底部位,并且从存储器重新加载值将对其进行符号扩展,但许多编译器的优化可能会假设已签名的算法不会溢出,溢出的影响在许多真实场景​​中可能是不可预测的。 举一个简单的例子,在16位DSP上使用其一个32位累加器作为返回值(例如TMS3205X), int16_t foo(int16_t bar) { return bar+1;}编译器可以自由加载bar ,sign -extended,进入累加器,添加一个,然后返回。 如果调用代码是例如long z = foo(32767) ,则代码可以很好地将z设置为32768而不是-32768。