当Byte溢出时实际发生了什么?

当Byte溢出时实际发生了什么?

说我们有

byte byte1 = 150; // 10010110 byte byte2 = 199; // 11000111 

如果我们现在做这个添加

 byte byte3 = byte1 + byte2; 

我想我们最终会得到byte3 = 94,但究竟发生了什么? 我是否以某种方式覆盖了其他内存或者这完全无害?

这很简单。 它只是添加并以超过8位的数字出现。 第九位(一个)只是“掉落”而剩下的8位形成数字94。

(是的,这是无害的)

在C#中,如果你有

  checked { byte byte3 = byte1 + byte2; } 

它会抛出溢出exception。 默认情况下,代码编译unchecked 。 正如其他答案所说,价值将“环绕”。 即, byte3 = (byte1 + byte2) & 0xFF;

顶部位将被截断。 它对任何其他记忆都没有害处,只会对意外结果造成伤害。

进位标志设置…但除了结果不是你所期望的,应该没有不良影响。

通常(并且确切的行为将取决于语言和平台),结果将采用模256进行。 即150 + 199 = 349. 349 mod 256 = 93。

这不应该影响任何其他存储。

既然您已经标记了C#,C ++和C的问题,我将回答有关C和C ++的问题。 在签名类型的c ++溢出中,包括sbyte (我相信,它是C / C ++中的signed char )会导致未定义的行为。 但是对于无符号类型,例如byte (在C ++中是unsigned char ),结果取模2 n ,其中n是无符号类型中的位数。 在C#中,第二个规则成立,如果签名类型位于checked块中,则会生成exception。 我可能在C#部分错了。

在c#中溢出是无害的 – 你不会溢出内存 – 你只需要获得结果的最后8位。 如果您希望这是一个例外,请使用’checked’关键字。 另请注意,您可能会发现byte + byte给出int,因此您可能需要转换回byte。

行为取决于语言。

在C和C ++中,有符号溢出未定义,无符号溢出具有您提到的行为(尽管没有byte类型)。

在C#中,您可以使用checked关键字明确表示您希望在出现溢出时收到exception,并且unchecked关键字明确表示您要忽略它。

领先的位置刚刚下降。

并且发生算术溢出。 由于150 + 199 = 349,二进制1 0101 1101,高1位被丢弃,字节变为0101 1101; 即一个字节可以保持溢出的位数。

没有造成任何损坏 – 例如, 内存没有溢出到另一个位置。

让我们看看实际发生了什么(在C中(假设您已经获得了相应的数据类型,因为有些人已经指出C没有“byte”数据类型;但是,有8位数据类型可以添加)) 。 如果在堆栈上声明这些字节,则它们存在于主存储器中; 在某些时候,字节将被复制到处理器进行操作(我正在跳过几个重要的步骤,例如进程缓存…)。 一旦进入处理器,它们将被存储在寄存器中; 处理器将对这两个寄存器执行添加操作以将数据添加到一起。 这是造成混乱的原因所在。 CPU将以本机(有时是指定的)数据类型执行添加操作。 假设CPU的本机类型是32位字(并且该数据类型是用于添加操作的数据类型); 这意味着这些字节将以32位字存储,高24位未设置; 添加操作确实会在目标32位字中执行溢出。 但是(这里是重要的一点)当数据从寄存器复制回堆栈时,只有最低8位(字节)将被复制回堆栈上的目标变量位置。 (注意,字节打包和堆栈也有一些复杂性。)

所以,这是结果; add会导致溢出(取决于所选的特定处理器指令); 但是,数据会从处理器复制到适当大小的数据类型中,因此溢出是看不见的(并且假设编写正确的编译器,则无害)。

就C#而言,将两个类型为byte的值一起添加会产生int类型的值,然后必须将其强制转换回byte

因此,您的代码示例将导致编译器错误,而不会返回到字节,如下所示。

 byte byte1 = 150; // 10010110 byte byte2 = 199; // 11000111 byte byte3 = (byte)(byte1 + byte2); 

有关详细信息 , 请参阅MSDN 。 另请参阅C#语言规范 ,第7.3.6节“数字促销”。