POSIX在stdint.h中的"two's complement representation"是什么意思?

What does POSIX mean by "two's complement representation" in stdint.h?

众所周知,有符号整数溢出会引发未定义的行为,并且有符号整数的按位操作充其量是不可靠的。因此,我发现 the POSIX standard 中的这一行相当奇怪:

The typedef name int N _t designates a signed integer type with width N, no padding bits, and a two's-complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.

这是一个相当模糊的陈述,可能意味着这些事情的任意组合:

  1. intN_t的范围是INTN_MININTN_MAX
  2. sizeof(intN_t) == N/8
  3. intN_t 上的按位运算按照二进制补码表示的预期方式运行。 -1 ^ x == ~x 对于每个 x,在到处插入 intN_t 转换之后。
  4. intN_t 不能有陷阱表示(并且优化编译器不能利用可能的陷阱)。
  5. intN_t 变量的溢出是已定义的行为(并从 INTN_MAX 回绕到 INTN_MIN)。
根据文档的其余部分,

(1) 和 (2) 对我来说显然都是正确的。 (1) 由 INTN_MIN/MAX 的定义明确指定。 (2) 隐含于 "no padding bits."

POSIX 要求 (3)、(4) 和 (5) 中的哪一个?

TL;DR

134 在任何 C99、C11 编译器上都是正确的,其中 intN_t存在。 2 在存在 int8_t 的任何 C11 编译器上都是正确的 - 因为 int8_t 的存在意味着 CHAR_BIT 是 8。 5 C 特别不需要 - 有符号整数溢出的行为未定义。

POSIX 限制了允许的 C 实现,因此 CHAR_BIT 必须是 8 并且整数表示是二进制补码。因此,POSIX 平台上的兼容 C99/C11 编译器必须具有 int8_t,这使得语句 1234 在 POSIX 上为真。由于 POSIX 没有说明有符号整数溢出,它仍未定义,因此 5 为假。


引用的句子逐字取自C11(C99)标准。 C11 7.20.1.1p1:

The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes such a signed integer type with a width of exactly 8 bits.

int8_t 在 C 中是 optional,因此标准中仅存在此片段甚至不需要 2 的补码表示。 C11 7.20.1.1p3:

These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two's complement representation, it shall define the corresponding typedef names.

在您的原始陈述中,

  1. 当然是对的,但是从二的补码表示就不能得出这样的结论。 int 的范围也从 INT_MININT_MAX 在任何人的补充体系结构上。但是,由此得出的结论是 INTN_MIN 的值为 .

  2. 遵循补码表示sizeof(intN_t)N / CHAR_BIT。然而,POSIX 要求 CHAR_BIT 是 8 所以 sizeof(intN_t) 确实是 N / 8

  3. 这是补码表示法

  4. 的唯一结果
  5. 来自二进制补码表示,而是 2 的补码的组合并且没有填充位.

  6. 遵循二进制补码表示两者都不是 C 所要求的也不 POSIX.


类型int8_t不是POSIX指定的而是POSIX采用和扩充的C99、C11。 POSIX 增加两个限制: * CHAR_BIT 必须恰好为 8 且不能大于 8,即使 C 编程语言允许 * 整数的补码或符号和大小表示是不允许的,即使 C 编程语言允许它们

C99、C11 指定 如果存在 ,类型 intN_t 必须有这么多位,没有填充位和 2 的补码。如果int8_t存在,它的sizeof一定是1,因为它是signed char then的同义词,CHAR_BIT等于8。

不会有 intN_t 的陷阱表示,但这并不意味着那些 不确定 值的对象必须具有相同的值,或者将这些值传递给库函数将具有定义的行为。考虑以下片段:

int32_t *foo = malloc(sizeof(int32_t));
printf(PRId32 "\n", *foo);
printf(PRId32 "\n", *foo);
free(foo);

编译器甚至不需要调用malloc;它可以将其编译为 puts("42\n666"); 的等价物——即使没有 int32_t 类型的陷阱值。这是因为 malloc:

[...] allocates space for an object whose size is specified by size and whose value is indeterminate.

不确定的真正意思是unstable; indeterminable


有符号整数溢出的行为始终未定义。