13

如果对 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 位的有符号整数类型。

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

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

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

2 回答 2

13

不,它没有。

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

中的类型<stdint.h>只是现有类型的 typedef(别名)。添加 typedef 不会改变类型的行为。

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

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

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

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

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

于 2012-02-20T19:29:56.013 回答
4

尽管将超出范围的值存储到内存中的有符号类型通常会存储该值的低位,并且从内存中重新加载该值会对其进行符号扩展,但许多编译器的优化可能会假设有符号算术不会溢出,并且在许多实际场景中溢出的影响可能是不可预测的。举个简单的例子,在一个 16 位 DSP 上,它使用一个 32 位累加器作为返回值(例如 TMS3205X),int16_t foo(int16_t bar) { return bar+1;}编译器可以自由地bar将. 如果调用代码是 eg long z = foo(32767),则代码很可能设置z为 32768 而不是 -32768。

于 2013-05-11T00:11:35.420 回答