字节溢出时实际发生了什么?
说我们有
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
如果我们现在添加
byte byte3 = byte1 + byte2;
我认为我们最终会得到byte3 = 94,但究竟发生了什么?我是否以某种方式覆盖了其他内存,或者这是完全无害的?
答案 0 :(得分:11)
这很简单。它只是添加并以超过8位的数字出现。第九位(一个)只是“掉落”,剩下的8位形成数字94.
(是的,这是无害的)
答案 1 :(得分:7)
如果你有C#,
checked { byte byte3 = byte1 + byte2; }
它将抛出溢出异常。默认情况下,代码编译为unchecked
。正如其他答案所说,价值将“环绕”。即,byte3 = (byte1 + byte2) & 0xFF;
答案 2 :(得分:6)
顶部位将被截断。它对任何其他记忆都没有害处,只会对意外结果造成伤害。
答案 3 :(得分:5)
进位标志设置...但除了结果不符合您的预期外,应该没有不良影响。
答案 4 :(得分:5)
通常(并且确切的行为将取决于语言和平台),结果将采用模256进行。即150 + 199 = 349. 349 mod 256 = 93。
这不应影响任何其他存储。
答案 5 :(得分:5)
由于您已经标记了C#,C ++和C的问题,我将回答有关C和C ++的问题。在签名类型的c ++溢出中,包括sbyte
(我相信,在C / C ++中是signed char
)会导致未定义的行为。但是对于无符号类型,例如byte
(在C ++中为unsigned char
),结果取模2 n ,其中n是无符号类型中的位数。在C#中,第二个规则成立,如果签名类型位于checked
块中,则会生成异常。我可能在C#部分错了。
答案 6 :(得分:4)
溢出在c#中是无害的 - 你不会溢出内存 - 你只需要获得结果的最后8位。如果您希望这是一个例外,请使用'checked'关键字。另请注意,您可能会发现byte + byte给出int,因此您可能需要转换回byte。
答案 7 :(得分:3)
行为取决于语言。
在C和C ++中,有符号溢出未定义,无符号溢出具有您提到的行为(尽管没有byte
类型)。
在C#中,您可以使用checked
关键字明确表示您希望在出现溢出时收到异常并unchecked
关键字明确表示您要忽略它。
答案 8 :(得分:2)
领先位刚刚下降。
答案 9 :(得分:2)
发生算术溢出。由于150 + 199 = 349,二进制1 0101 1101,高1位被丢弃,字节变为0101 1101;即一个字节可以保持溢出的位数。
没有造成任何损害 - 例如内存没有溢出到另一个位置。
答案 10 :(得分:1)
让我们看看实际发生了什么(在C中(假设您已经获得了相应的数据类型,因为有些人已经指出C没有“byte”数据类型;但是,有8位数据类型可以是添加))。如果在堆栈上声明这些字节,则它们存在于主存储器中;在某些时候,字节将被复制到处理器进行操作(我正在跳过几个重要的步骤,例如processsor缓存......)。一旦进入处理器,它们将被存储在寄存器中;处理器将对这两个寄存器执行添加操作以将数据添加到一起。 这里出现混淆的原因。 CPU将以本机(有时是指定的)数据类型执行添加操作。假设CPU的本机类型是32位字(并且该数据类型是用于添加操作的数据类型);这意味着这些字节将以32位字存储,高24位未设置;添加操作确实会在目标32位字中执行溢出。但是(这里是重要的一点)当数据从寄存器复制回堆栈时,只有最低8位(字节)将被复制回堆栈上的目标变量位置。 (注意,字节打包和堆栈也有一些复杂性。)
所以,这就是结果; add会导致溢出(取决于所选的特定处理器指令);但是,数据会从处理器复制到适当大小的数据类型中,因此溢出是看不见的(并且假设编写正确的编译器,则无害)。
答案 11 :(得分:1)
就C#而言,添加两个byte
类型的值会产生int
类型的值,然后必须将其转换回byte
。
因此,您的代码示例将导致编译器错误,而不会返回到字节,如下所示。
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
byte byte3 = (byte)(byte1 + byte2);
See MSDN for more details就此而言。另请参阅C# language specification,第7.3.6节“数字促销”。