2015-05-08 126 views
0

我正在阅读的一本c编程书(c编程,现代方法第2版)说,当在无符号整数运算期间发生溢出时,结果是定义“。为什么整数在溢出时有不同的行为

这里是一个小的代码示例

#include <stdio.h> 

int main() 
{ 
    unsigned short int x = 65535; // The unsigned short int is at the maximum possible range 
    x += 1; // If I add one to it will overflow. 
    printf("%u", x); // the output will be zero or one if decide to add plus one again to x 
    return 0; 
} 

他接着说,“为有符号整数,这些整数的行为没有定义”。这意味着程序可以打印出错误的结果,也可能导致程序崩溃。

这是为什么?

+1

你问为什么有符号整数溢出的行为是未定义的,(*因为语言规范说它是*),或为什么规范定义无符号整数溢出但声明有符号整数溢出未定义(* [签署的值](http://stackoverflow.com/questions/18195715/why-is-unsigned-integer-overflow-defined-behavior-but-signed-integer-overflow-is)*)?另外,请不要使用'%d'打印无符号值 - 出于某种原因,'%u'存在。 –

+0

@IskarJarak“为什么规范定义了无符号整数溢出,但声明了有符号整数溢出未定义?”你的这句话是我问的。 –

+0

@LuisAverhoff然后看到重复的链接。这已经被问过。 –

回答

3

它涉及到硬件表示,并且有多种方法来表示二进制符号整数类型(符号幅度,补码,二进制补码)以及对它们的操作。当发生溢出时(例如,触发硬件陷阱,使用模数等),这些具有完全不同的含义。

所有以二进制表示无符号整型值并在这些值上实现数值运算的明显方法都具有相同的结果 - 本质上,硬件中的数值运算使用模运算。

对于基本类型(以及其他事物),当存在多种可行的实现方式时,标准通常允许编译器供应商自由,而这些选项具有不同的后果。有多种签名整数类型的方法,以及使用每种方法的现实世界的硬件。它们足够不同以保证行为没有定义(因为该术语在标准中定义)。

+0

这个答案完全正确。另外值得一提的是,不幸的是,因为该标准表明行为没有定义,所以编译器供应商可以做任何事情*。通过在C中添加来溢出一个带符号的int不一定要做你的CPU的ADD指令在溢出时所做的。已知优化器利用这种不确定性并完全优化加法。国际海事组织这是一个危险的游戏玩规格。 – StilesCrisis

+0

是的。我会考虑这个问题,但我首先想到的是,考虑到原来的问题,这有点远。你所描述的是一种自我实现的预言,有时与未定义的行为相关联(由于存在一系列现实世界的行为,标准中没有定义标准,因为它没有定义,实施者选择支持更多可能的行为)。然而,这是一些未定义的结果,而不是它首先未定义的原因。 – Peter

+0

对我来说,“不确定是因为不同的CPU有不同的行为”这个明显的推论是“C编译器会遵循我的CPU架构的行为”,但实际情况要微妙得多。这是一个陷阱。 – StilesCrisis