众所周知,有符号整数溢出会调用未定义的行为,并且对有符号整数的逐位操作最多也是不可靠的。因此,我发现the POSIX standard中的这一行很奇怪:
typedef 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
。{/ li>
intN_t
不能有陷阱表示(优化编译器不得利用可能的陷阱)。intN_t
变量的溢出是已定义的行为(并从INTN_MAX
换行到INTN_MIN
)。(1)和(2)对我来说都显得非常明显。 (1)由INTN_MIN
/ MAX
的定义明确指定。 (2)隐含在"没有填充位。"
POSIX是否需要(3),(4)和(5)中的哪一个?
答案 0 :(得分:9)
TL; DR
在<{1}}存在的任何C99,C11编译器中, 1 , 3 , 4 为true。 2 在任何存在intN_t
的C11编译器中都是如此 - 因为int8_t
的存在意味着int8_t
为8。 5 特别是C不需要 - 未定义有符号整数溢出的行为。
POSIX限制允许的C实现,以便CHAR_BIT
必须为8,整数表示是2的补码。因此,POSIX平台上的兼容C99 / C11编译器必须具有CHAR_BIT
,这使得语句 1 , 2 , 3 和<在POSIX上为true> 4 为true。由于POSIX没有说明有符号整数溢出,因此它仍未定义,因此 5 为假。
引用的句子是从C11(C99)标准中取得 verbatim 。 C11 7.20.1.1p1:
typedef名称
int8_t
指定有符号整数类型,宽度为intN_t
,没有填充位,以及二进制补码表示。因此,N
表示这样的有符号整数类型,其宽度恰好为8位。
int8_t
在C中是可选,因此标准中仅存在此片段甚至不需要2的补码表示。 C11 7.20.1.1p3:
这些类型是可选的。但是,如果实现提供宽度为8,16,32或64位的整数类型,没有填充位,并且(对于具有二进制补码表示的有符号类型),它应定义相应的typedef名称。
你原来的陈述,
当然是正确的,但这样的事情并不是来自两个补充表示。任何一个补码架构上的int8_t
范围从int
到INT_MIN
。但是,由此得出的结论是INT_MAX
的值为。
不来自两个补码表示。 INTN_MIN
是sizeof(intN_t)
。但是,POSIX要求N / CHAR_BIT
为8,因此CHAR_BIT
确实是sizeof(intN_t)
这是两个补充表示
不来自一个二进制补码,但是2&是补码的组合,并且没有填充位。
不跟随双向补充表示,既不是C也不是POSIX 。< / p>
POSIX没有指定类型N / 8
,而是POSIX采用和扩充的C99,C11。 POSIX增加了两个限制:
*即使C编程语言允许,int8_t
必须精确为8而不是更大
*不允许使用单数补码或整数的符号和幅度表示,即使它们是C编程语言允许的
C99,C11指定如果存在,类型CHAR_BIT
必须具有完全如此多的位,没有填充位,以及2&#39; s补码。如果intN_t
存在,则其int8_t
必须为1,因为它是sizeof
的同义词,然后signed char
等于8。
不会有CHAR_BIT
的陷阱表示,但它并不意味着具有明确不确定值的那些对象必须具有相同的值,或者传递库函数的这些值将具有已定义的行为。请考虑以下片段:
intN_t
编译器甚至不需要调用int32_t *foo = malloc(sizeof(int32_t));
printf(PRId32 "\n", *foo);
printf(PRId32 "\n", *foo);
free(foo);
;即使没有malloc
类型的陷阱值,它也可以将其编译为等效的puts("42\n666");
。这是因为malloc
:
[...]为大小由大小指定的对象分配空间,的值为不确定。
不确定意味着unstable; indeterminable
有符号整数溢出的行为始终未定义。