算术溢出是否等效于模运算?

avm*_*han 25 c overflow modulo integer-arithmetic

我需要在C中进行模256运算.所以我可以简单地做

unsigned char i;
i++;
Run Code Online (Sandbox Code Playgroud)

代替

int i;
i=(i+1)%256;
Run Code Online (Sandbox Code Playgroud)

Ale*_* C. 25

没有.没有什么可以保证unsigned char有八位.使用uint8_t<stdint.h>,你会完全恢复健康的.这需要一个支持的实现stdint.h:任何符合C99的编译器都可以,但是较旧的编译器可能不提供它.

注意:无符号算术永远不会溢出,并且表现为"modulo 2 ^ n".带有未定义行为的带符号算术溢出.

  • @Floris:是的,但是一个C字节不一定是8位.它被*定义为*`char`的大小. (10认同)
  • OP甚至没有提到他所针对的那种机器,所以你只是不知道,你应该在答案中指明这一点; 其他人也可能需要这条信息. (2认同)
  • @ user2485710:完成.由于字节技巧在这种环境中很常见,因此确实需要谨慎. (2认同)
  • @PaulGriffiths:我所知道的一个例子是特定的16位德州仪器DSP嵌入式平台,它只支持字寻址,因此一切至少为16位.`sizeof(char)== sizeof(short)== sizef(int)== 1 == 16 bits`.这个答案中提出的假设在那里不起作用. (2认同)

Lih*_*ihO 6

是的,两个示例的行为都是相同的.见C996.2.5§9:

涉及无符号操作数的计算永远不会溢出,因为无法通过生成的无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模.


Kei*_*son 5

很可能是,但是在这种情况下这样做的原因实际上相当复杂。

unsigned char i = 255;
i++;
Run Code Online (Sandbox Code Playgroud)

i++相当于i = i + 1

(好吧,几乎。递增之前i++产生的值,因此它实际上等于。但是由于在这种情况下结果被丢弃,因此不会引起任何其他问题。)i (tmp=i; i = i + 1; tmp)

由于unsigned char是窄类型,因此将unsigned char运算+符提升为操作数int(假设int可以将所有可能的值保存在的范围内unsigned char)。因此,如果i == 255UCHAR_MAX == 255,则加法的结果为256,并且类型为(signed)int

赋值256从隐式转换intunsigned char。转换为无符号类型的定义很明确;结果以模为模MAX+1,其中MAX是目标无符号类型的最大值。

如果i被声明为unsigned int

unsigned int i = UINT_MAX;
i++;
Run Code Online (Sandbox Code Playgroud)

不会进行类型转换,但是+无符号类型的运算符的语义指定了缩减模块MAX+1

请记住,分配给的值在i数学上等于(i+1) % UCHAR_MAXUCHAR_MAX通常 255,并且保证是至少 255,但是它可以合法更大。

可能会有一个奇异的系统,该系统UCHAR_MAX也无法存储在一个已签名的int对象中。这将要求UCHAR_MAX > INT_MAX,这意味着系统将必须至少具有 16位字节。在这样的系统上,升级将是从unsigned charunsigned int。最终结果将是相同的。您不太可能遇到这样的系统。我认为某些字节大于8位的DSP有C实现。字节中的位数由中CHAR_BIT定义<limits.h>

CHAR_BIT > 8不一定暗示UCHAR_MAX > INT_MAX。例如,您可以拥有CHAR_BIT == 16and(sizeof (int) == 2即16位字节和32位int)。


oua*_*uah 5

unsigned char c = UCHAR_MAX;
c++;
Run Code Online (Sandbox Code Playgroud)

基本上是的,没有溢出,但不是因为c是无符号类型.有一个隐藏的推广cint这里,并从整数转换intunsigned char,它是完美的定义.

例如,

 signed char c = SCHAR_MAX;
 c++;
Run Code Online (Sandbox Code Playgroud)

也不是未定义的行为,因为它实际上相当于:

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

和从转换intsigned char由实现定义在这里(见C99,整数转换6.3.1.3p3).CHAR_BIT == 8假设是简化的.

有关上述示例的更多信息,我建议您阅读以下文章:

"来自地狱的小C功能"

http://blog.regehr.org/archives/482