众所周知,有符号整数溢出会调用未定义的行为,并且有符号整数的按位操作充其量是不可靠的。因此,我发现 the POSIX standard 中的这一行相当奇怪:
这是一个相当模糊的陈述,这可能意味着这些事情的任何组合:
intN_t
的范围是从 INTN_MIN
到 INTN_MAX
。 sizeof(intN_t) == N/8
intN_t
上的按位运算的行为与二进制补码表示的预期一致。每个 -1 ^ x == ~x
的 x
,在插入 intN_t
后会在任何地方进行转换。 intN_t
不能有陷阱表示(并且优化编译器不能利用可能的陷阱)。 intN_t
变量的溢出是定义的行为(并从 INTN_MAX
包装到 INTN_MIN
)。 根据文档的其余部分,(1) 和 (2) 对我来说显然是正确的。 (1) 由
INTN_MIN
/MAX
的定义明确指定。 (2) 由“无填充位”暗示。POSIX 需要 (3)、(4) 和 (5) 中的哪一个(如果有)?
最佳答案
TL; 博士
1 、 3 、 4 在任何存在 intN_t
的 C99、C11 编译器上都为真。 2 在任何存在 int8_t
的 C11 编译器上都为真——因为 int8_t
的存在意味着 CHAR_BIT
是 8。 5 C 没有特别要求——对有符号整数溢出的行为未定义。
POSIX 限制了允许的 C 实现,因此 CHAR_BIT
必须是 8 并且整数表示是二进制补码。因此,POSIX 平台上的兼容 C99/C11 编译器必须具有 int8_t
,这使得语句 1 、 2 、 3 和 4 为真。由于 POSIX 没有说明有符号整数溢出,它仍然未定义,因此 5 是假的。
引用的句子逐字取自 C11 (C99) 标准。 C11 7.20.1.1p1 :
int8_t
在 C 中是可选的,所以在标准中仅仅存在这个片段甚至不需要 2 的补码表示。 C11 7.20.1.1p3 :
在你的原始陈述中,
int
的范围也从 INT_MIN
到 INT_MAX
在任何互补架构上。但是,由此得出的结论是 INTN_MIN
具有 value 。 sizeof(intN_t)
是 N / CHAR_BIT
。然而,POSIX 要求 CHAR_BIT
是 8 所以 sizeof(intN_t)
确实是 N / 8
int8_t
类型不是由 POSIX 指定的,而是由 POSIX 采用和扩充的 C99、C11。 POSIX 增加了两个限制:* 即使 C 编程语言允许,
CHAR_BIT
必须恰好为 8 且不能大于 8* 整数的补码或符号和大小表示是不允许的,即使它们被 C 编程语言允许
C99、C11 指定如果存在,类型
intN_t
必须有这么多位,没有填充位,以及 2 的补码。如果 int8_t
存在,则其 sizeof
必须为 1,因为它是 signed char
的同义词,那么 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
:不确定真的意味着 unstable; indeterminable
有符号整数溢出的行为始终未定义。
关于c - stdint.h 中 "two' 的补码表示形式的 POSIX 是什么意思?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45583656/