设置为 CHAR_MAX 的字符值是否保证环绕到 CHAR_MIN?

Lon*_*ner 10 c standards integer-overflow char language-lawyer

我的代码:

#include <stdio.h>
#include <limits.h>

int main()
{
    char c = CHAR_MAX;
    c += 1;
    printf("CHAR_MIN=%d CHAR_MAX=%d c=%d (%c)\n", CHAR_MIN, CHAR_MAX, c, c);
}
Run Code Online (Sandbox Code Playgroud)

输出:

CHAR_MIN=-128 CHAR_MAX=127 c=-128 ()
Run Code Online (Sandbox Code Playgroud)

我们看到,当我们增加一个char设置为的变量时CHAR_MAX,它会环绕到CHAR_MIN。这种行为有保证吗?或者它将是未定义的行为或实现指定的行为?C99 标准对此有何评论?

[注意:将大于 CHAR_MAX (127) 的值赋予 charC会发生什么-为什么 char c=129 会转换为 -127?没有解决这个问题,因为他们谈论分配一个超出范围的值而不是将一个值增加到一个超出范围的值。]

Ant*_*ala 15

问题是双重的:首先,是

char c = CHAR_MAX;
c += 1;
Run Code Online (Sandbox Code Playgroud)

评价不同

char c = CHAR_MAX;
c = c + 1;
Run Code Online (Sandbox Code Playgroud)

答案是否定的,因为C11/C18 6.5.16.2p3

  1. 这种形式的复合赋值E1 op = E2等价于简单赋值表达式,E1 = E1 op (E2)只是左值E1只计算一次,并且对于不确定顺序的函数调用,复合赋值的操作是一次计算。如果E1具有原子类型,则复合赋值是具有memory_order_seq_cst内存顺序语义的读-修改-写操作。113)

然后,问题是c = c + 1. 这里的操作数+进行通常的算术转换,并且c1因此被提拔到int,除非实在古怪的架构要求char被提升为unsigned int+然后对的计算进行评估,并将int/类型的结果unsigned int转换回char并存储在 中c

3 种实现定义的方法可以对其进行评估:

  • CHAR_MIN是 0,因此char是无符号的。

    char然后要么被提升为intor unsigned int,如果它被提升为 an int,那么CHAR_MAX + 1也必然适合 an int,并且不会溢出,或者如果unsigned int它可能适合或环绕为零。当结果值,即在数值上CHAR_MAX + 10模约减后,回到 时c,模约减后将变为 0,即CHAR_MIN

  • 否则char是有符号的,则如果CHAR_MAX 小于INT_MAX,则结果CHAR_MAX + 1将适合int,并且标准C11/C18 6.3.1.3p3适用于分配时发生的转换:

    1. 否则,新类型是有符号的,值不能在其中表示;要么结果是实现定义的,要么引发实现定义的信号。
  • 或者,iff sizeof (int) == 1 and char是有符号的,然后char被提升为 an int,而CHAR_MAX == INT_MAX=>CHAR_MAX + 1将导致整数溢出并且行为将是 undefined

即可能的结果是:

  • 如果char是无符号整数类型,则结果始终为0,即CHAR_MIN

  • 否则char是有符号整数类型,行为是实现定义的/未定义的:

    • CHAR_MIN 或其他一些实现定义的值,
    • 引发了一个实现定义的信号,可能会终止程序,
    • 或者行为在某些平台上未定义,其中sizeof (char) == sizeof (int).

所有的增量业务c = c + 1c += 1c++并且++c具有相同的平台上相同的副作用。表达式的计算值c++将是c增量前的值;对于其他三个,它将是c增量后的值。

  • @sepp2k `&lt;pedantic&gt;`不知道`CHAR_BITS`,但`CHAR_BIT`会`&gt;= 16&lt;/pedantic&gt;`。 (3认同)
  • 默认情况下“char”应始终无符号的又一个原因。 (2认同)