Kev*_*vin 4 c posix language-lawyer
众所周知,有符号整数溢出会调用未定义的行为,并且对有符号整数的按位操作最多也是不可靠的.因此,我发现POSIX标准中的这一行很奇怪:
type_f name int N _t指定一个有符号整数类型,其宽度为N,没有填充位和二进制补码表示.因此,int8_t表示具有正好8位宽度的有符号整数类型.
这是一个相当模糊的陈述,可能意味着这些事情的任何组合:
intN_t是从.INTN_MIN到INTN_MAX.sizeof(intN_t) == N/8intN_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是在任何C11编译器,其中真正int8_t存在-因为存在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名称
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是有价值.
不遵循两个补码表示.sizeof(intN_t)是N / CHAR_BIT.但是,POSIX要求的确是CHAR_BIT8sizeof(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 charthen 的同义词并且CHAR_BIT等于8.
不会有陷阱表示intN_t但它并不意味着具有明确不确定值的那些对象必须具有相同的值,或者将这些值传递给库函数将具有已定义的行为.请考虑以下片段:
int32_t *foo = malloc(sizeof(int32_t));
printf(PRId32 "\n", *foo);
printf(PRId32 "\n", *foo);
free(foo);
Run Code Online (Sandbox Code Playgroud)
编译器甚至不需要调用malloc; 它可以将其编译为相当于puts("42\n666");- 即使没有类型的陷阱值int32_t.这是因为malloc:
[...]为一个对象分配空间,该对象的大小由大小指定,其值是不确定的.
不确定的确意味着不稳定; 无法确定
有符号整数溢出的行为始终未定义.