题
当字节溢出时会发生什么?
说我们有
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
如果我们现在做这个加法
byte byte3 = byte1 + byte2;
我认为我们最终会得到字节3 = 94,但实际发生了什么?我是否以某种方式覆盖了其他记忆,还是完全无害?
解决方案
这很简单。它只是进行了加法,并以超过8位的数字出现。第九位(是一个)只是“掉下来”,而您剩下的8位构成了数字94。
(是的,这是无害的)
其他提示
在C#中,如果您有
checked { byte byte3 = byte1 + byte2; }
它将引发溢出异常。代码已编译 unchecked
默认。正如其他答案所说的那样,价值将“缠绕”。 IE, byte3 = (byte1 + byte2) & 0xFF;
顶部将被截断。它对任何其他记忆都不是有害的,仅在意想不到的结果方面有害。
进位旗被设定了...但是除了结果不是您的期望之外,也不会有不良影响。
通常(确切的行为将取决于语言和平台),结果将被模拟256。 IE 150+199 =349。349mod 256 = 93。
这不应影响任何其他存储。
由于您已经标记了问题C#,C ++和C,因此我会回答有关C和C ++的问题。在签名类型的C ++溢出中,包括 sbyte
(我相信这是 signed char
在C/C ++中)导致不确定的行为。但是对于未签名类型,例如 byte
(那是 unsigned char
在C ++中)结果是Modulo 2n 其中n是无符号类型中的位数。在c#中,第二个规则保留,如果签名类型在 checked
堵塞。我在C#部分中可能错了。
C#中的溢出是无害的 - 您不会溢出内存 - 您只需获得结果的最后8位即可。如果您希望这个例外,请使用“检查”的关键字。还要注意,您可能会发现字节+字节给出INT,因此您可能需要抛弃到字节。
行为取决于语言。
在C和C ++中,签名的溢出是未定义的,未签名的溢出具有您提到的行为(尽管没有 byte
类型)。
在C#中,您可以使用 checked
明确说明您要收到异常的关键字,如果有溢出和 unchecked
明确说您要忽略它的关键字。
领先点刚刚下降。
并且算术溢出发生。由于150+199 = 349,二进制1 0101 1101,上部1位被删除,字节变为0101 1101;即一个字节可以保持溢出的位数。
没有造成损害 - 例如 记忆 没有溢出到另一个位置。
让我们看一下实际发生的情况(在C中(假设您有适当的数据类型,有人指出C没有“字节”数据类型;尽管如此,可以添加8位数据类型)))))))))) 。如果这些字节在堆栈上声明,则它们存在于主内存中。在某个时候,字节将被复制到处理器进行操作(我正在跳过几个重要步骤,例如ProcessSor缓存...)。进入处理器后,它们将存储在注册表中;处理器将对这两个寄存器执行一个添加操作,以将数据添加在一起。 这是发生混乱的原因。 CPU将在本机(或有时,指定)数据类型中执行添加操作。假设CPU的本机类型是32位单词(并且该数据类型是用于添加操作的方法);这意味着这些字节将存储在32位单词中,上部24位不设置;添加操作的确将在目标32位单词中进行溢出。但是(这是重要的位)当数据从寄存器从寄存器复制到堆栈时,只有最低的8位(字节)将复制回目标变量在堆栈上的位置。 (请注意,字节包装和这里的堆栈也有一些复杂性。)
因此,这是结果;添加会导致溢出(取决于选择的特定处理器指令);但是,将数据从处理器中复制到适当尺寸的数据类型中,因此溢出是看不见的(并且假设编写正确的编译器,则无害)。
就c#而言,添加两个类型值 byte
一起产生类型的值 int
然后必须归还 byte
.
因此,您的代码示例将导致编译器错误,而无需将字节放回以下内容。
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
byte byte3 = (byte)(byte1 + byte2);
有关更多详细信息,请参见MSDN 关于这个。另外,请参阅 C#语言规范, ,第7.3.6节数字促销。