当字节溢出时实际上会发生什么?
当字节溢出时实际上会发生什么?
如果我们
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
现在做这个加法,
byte byte3 = byte1 + byte2;
我想我们最终会得到 byte3 = 94 但实际上会发生什么?我是否以某种方式覆盖了其他一些内存,或者这完全无害?
What actually happens when a Byte overflows?
Say we have
byte byte1 = 150; // 10010110
byte byte2 = 199; // 11000111
If we now do this addition
byte byte3 = byte1 + byte2;
I think we'll end up with byte3 = 94 but what actually happens? Did I overwrite some other memory somehow or is this totally harmless?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
这很简单。它只是进行加法运算并得出一个超过 8 位的数字。第九位(即 1)刚刚“脱落”,剩下的 8 位形成了数字 94。
(是的,它是无害的)
It's quite simple. It just does the addition and comes off at a number with more than 8 bits. The ninth bit (being one) just 'falls off' and you are left with the remaining 8 bits which form the number 94.
(yes it's harmless)
顶部位将被截断。它不会对任何其他记忆造成损害,只会造成意想不到的结果。
The top bits will be truncated. It is not harmful to any other memory, it is only harmful in terms of unintended results.
在 C# 中,如果有
它将抛出溢出异常。默认情况下,代码是
未选中
编译的。正如其他答案所说,该值将“环绕”。即,byte3 = (byte1 + byte2) & 0xFF;
In C# if you have
It will throw an overflow exception. Code is compiled
unchecked
by default. As the other answers are saying, the value will 'wrap around'. ie,byte3 = (byte1 + byte2) & 0xFF;
进位标志被设置...但除了结果不是你所期望的之外,应该不会有任何不良影响。
The carry flag gets set... but besides the result not being what you expect, there should be no ill effects.
通常(确切的行为取决于语言和平台),结果将以 256 为模。即 150+199 = 349。349 mod 256 = 93。
这不应该影响任何其他存储。
Typically (and the exact behaviour will depend on the language and platform), the result will be taken modulo-256. i.e. 150+199 = 349. 349 mod 256 = 93.
This shouldn't affect any other storage.
由于您已将问题标记为 C#、C++ 和 C,所以我将回答有关 C 和 C++ 的问题。在 C++ 中,有符号类型的溢出,包括 sbyte(我相信在 C/C++ 中是有符号字符)会导致未定义的行为。然而,对于无符号类型,例如
byte
(C++ 中的unsigned char
),结果是取模 2n,其中 n 是无符号类型中的位。在 C# 中,第二条规则成立,如果签名类型位于checked
块中,则它们会生成异常。我在 C# 部分可能是错的。Since you have tagged your question C#, C++ and C, I'll answer about C and C++. In c++ overflow on signed types, including
sbyte
(which, I believe, issigned char
in C/C++) results in undefined behavior. However for unsigned types, such asbyte
(which isunsigned char
in C++) the result is takes modulo 2n where n is the number of bits in the unsigned type. In C# the second rule holds, and the signed types generate an exception if they are inchecked
block. I may be wrong in the C# part.溢出在 C# 中是无害的 - 你不会溢出内存 - 你只需得到结果的最后 8 位。如果您希望这是一个例外,请使用“checked”关键字。另请注意,您可能会发现 byte+byte 给出 int,因此您可能需要转换回 byte。
Overflow is harmless in c# - you won't overflow memory - you simply obly get the last 8 bits of the result. If you want this to this an exception, use the 'checked' keyword. Note also that you may find byte+byte gives int, so you may need to cast back to byte.
行为取决于语言。
在 C 和 C++ 中,有符号溢出是未定义的,无符号溢出具有您提到的行为(尽管没有
byte
类型)。在 C# 中,您可以使用
checked
关键字明确表示您希望在出现溢出时接收异常,并使用unchecked
关键字明确表示您希望忽略它。The behavior depends on the language.
In C and C++, signed overflow is undefined and unsigned overflow has the behavior you mentioned (although there is no
byte
type).In C#, you can use the
checked
keyword to explicitly say you want to receive an exception if there is overflow and theunchecked
keyword to explicitly say you want to ignore it.前导位刚刚脱落。
Leading bit just dropped off.
并且发生算术溢出。由于150+199=349,二进制1 0101 1101,去掉高1位,字节变成0101 1101;即一个字节可以容纳溢出的位数。
没有造成任何损坏 - 例如内存没有溢出到另一个位置。
And arithmetic overflow occurs. Since 150+199=349, binary 1 0101 1101, the upper 1 bit is dropped and the byte becomes 0101 1101; i.e. the number of bits a byte can hold overflowed.
No damage was done - e.g. the memory didn't overflow to another location.
让我们看看实际发生的情况(在 C 中(假设您已经有了适当的数据类型,正如一些人指出的那样,C 没有“字节”数据类型;尽管如此,还是可以添加 8 位数据类型)) 。如果这些字节在堆栈上声明,则它们存在于主内存中;在某些时候,字节将被复制到处理器进行操作(我跳过了几个重要的步骤,例如处理器或缓存......)。一旦进入处理器,它们将被存储在寄存器中;处理器将对这两个寄存器执行加法操作,将数据加在一起。 这就是发生混乱的原因。CPU 将以本机(或有时指定)数据类型执行添加操作。假设 CPU 的本机类型是 32 位字(并且该数据类型用于加法运算);这意味着这些字节将存储在 32 位字中,且高 24 位未设置;加法操作确实会在目标 32 位字中发生溢出。但是(这是重要的一点)当数据从寄存器复制回堆栈时,只有最低 8 位(字节)将被复制回堆栈上目标变量的位置。 (请注意,这里的字节打包和堆栈也涉及一些复杂性。)
因此,结果如下:添加导致溢出(取决于所选的特定处理器指令);然而,数据被从处理器复制到适当大小的数据类型中,因此溢出是看不见的(并且假设正确编写的编译器是无害的)。
Let's look at what actually happens (in C (assuming you've got the appropriate datatype, as some have pointed out that C doesn't have a "byte" datatype; nonetheless, there are 8-bit datatypes which can be added)). If these bytes are declared on the stack, they exist in main memory; at some point, the bytes will get copied to the processor for operation (I'm skipping over several important steps, such as processsor cacheing...). Once in the processor, they will be stored in registers; the processor will execute an add operation upon those two registers to add the data together. Here's where the cause of confusion occurs. The CPU will perform the add operation in the native (or sometimes, specified) datatype. Let's say the native type of the CPU is a 32-bit word (and that that datatype is what is used for the add operation); that means these bytes will be stored in 32-bit words with the upper 24 bits unset; the add operation will indeed do the overflow in the target 32-bit word. But (and here's the important bit) when the data is copied back from the register to the stack, only the lowest 8 bits (the byte) will be copied back to the target variable's location on the stack. (Note that there's some complexity involved with byte packing and the stack here as well.)
So, here's the upshot; the add causes an overflow (depending on the specific processor instruction chosen); the data, however, is copied out of the processor into a datatype of the appropriate size, so the overflow is unseen (and harmless, assuming a properly written compiler).
就 C# 而言,将两个
byte
类型的值相加会产生一个int
类型的值,然后必须将其强制转换回byte
。因此,您的代码示例将导致编译器错误,而不会转换回字节,如下所示。
有关此内容的更多详细信息,请参阅 MSDN。另请参阅 C# 语言规范的 7.3.6 数字提升部分。
As far as C# goes, adding two values of type
byte
together results in a value of typeint
which must then be cast back tobyte
.Therefore your code sample will result in a compiler error without a cast back to byte as in the following.
See MSDN for more details on this. Also, see the C# language specification, section 7.3.6 Numeric promotions.