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



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

  • intN_t 的范围是从 INTN_MININTN_MAX
  • sizeof(intN_t) == N/8
  • intN_t 上的按位运算的行为与二进制补码表示的预期一致。每个 -1 ^ x == ~xx ,在插入 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_MININT_MAX 在任何互补架构上。但是,由此得出的结论是 INTN_MIN 具有 value 。
  • 不遵循 二进制补码表示 sizeof(intN_t)N / CHAR_BIT 。然而,POSIX 要求 CHAR_BIT 是 8 所以 sizeof(intN_t) 确实是 N / 8
  • 这是 二进制补码表示的唯一结果
  • 不是 遵循 的二进制补码表示 而是 2 的补码的组合并且没有填充位。
  • 不遵循 的二进制补码表示 ,并且 既不是 C 也不是 POSIX

  • 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/

    10-12 23:57