[英]What does POSIX mean by “two's complement representation” in stdint.h?
众所周知,有符号整数溢出会调用未定义的行为,并且对有符号整数的按位操作最多也是不可靠的。 因此,我发现POSIX标准中的这一行很奇怪:
type_f name int N _t指定一个有符号整数类型,其宽度为N,没有填充位和二进制补码表示。 因此,int8_t表示具有正好8位宽度的有符号整数类型。
这是一个相当模糊的陈述,可能意味着这些事情的任何组合:
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; DR
1,3,4是真实的任何C99,C11编译器在哪里intN_t
存在。 2在任何存在int8_t
C11编译器中都是如此 - 因为int8_t
的存在意味着CHAR_BIT
为8. 5特别是C不需要 - 未定义有符号整数溢出的行为。
POSIX限制允许的C实现,以便CHAR_BIT
必须为8,整数表示为2的补码。 因此在POSIX平台兼容C99 / C11编译器必须有int8_t
,这使得语句1,2,3和4上POSIX真。 由于POSIX没有说明有符号整数溢出,因此它仍未定义,因此5为假。
引用的句子是从C11(C99)标准逐字逐句采用的。 C11 7.20.1.1p1 :
typedef name
intN_t
指定一个有符号整数类型,其宽度为N
,没有填充位和二进制补码表示 。 因此,int8_t
表示这样的带符号整数类型,其宽度恰好为8位。
int8_t
在C中是可选的,因此标准中仅存在此片段甚至不需要2的补码表示。 C11 7.20.1.1p3 :
这些类型是可选的。 但是,如果实现提供宽度为8,16,32或64位的整数类型,没有填充位,并且(对于具有二进制补码表示的有符号类型),它应定义相应的typedef名称。
在你的原始陈述中,
当然是正确的,但是这样的事情并不是来自两个补码表示 。 在任何一个补码架构上, int
范围从INT_MIN
到INT_MAX
。 但是,由此得出的INTN_MIN
是INTN_MIN
具有值 。
不遵循两个补码表示 。 sizeof(intN_t)
是N / CHAR_BIT
。 但是,POSIX要求CHAR_BIT
为8,因此sizeof(intN_t)
确实是N / 8
这是两个补码表示中唯一的结果
不是来自二进制补码表示,而是二进制补码的组合,并且没有填充位。
不是来自二进制补码表示 ,并且C和POSIX都不需要。
类型int8_t
不是由POSIX指定的,而是由POSIX采用和扩充的C99,C11。 POSIX增加了两个限制:* CHAR_BIT
必须精确为8而不是更大,即使C编程语言允许*也不允许使用一个补码或整数的符号和幅度表示,即使它们被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
:
[...]为一个对象分配空间,该对象的大小由大小指定, 其值是不确定的 。
有符号整数溢出的行为始终未定义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.