【问题标题】:What actually happens when a Byte overflows?当一个字节溢出时实际发生了什么?
【发布时间】:2010-11-11 16:56:14
【问题描述】:

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

说我们有

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

如果我们现在做这个添加

byte byte3 = byte1 + byte2;

我认为我们最终会得到 byte3 = 94 但实际上会发生什么?我是否以某种方式覆盖了其他一些记忆,或者这完全无害?

【问题讨论】:

  • 删除了 C 和 C++ 标签,因为 A. C 和 C++ 没有“字节”数据类型,并且 B. 根据标准,这是未定义的行为。
  • @Billy 在 C 和 C++ 中有等价物
  • 此代码无法编译。当你修复它时,运行时发生的事情也会变得很清楚。这是假设您的 [c#] 标签是准确的。
  • @Armen:是的,但是在 C 和 C++ 中,结果不是“93”,而是“未定义的行为”。因此,违反了问题的基本原则。 @ImJames:你没有让任何人不高兴。我只是不想让在有人过来摘下标签时不高兴;)
  • @Steve:我不知道其他领域,但是任何曾经在 C 中从事通信编程的人 typedef 将一个字节作为无符号 8 位值比您说“编译”要快。

标签: c# byte carryflag


【解决方案1】:

这很简单。它只是进行加法运算,并得出一个超过 8 位的数字。第 9 位(为 1)只是“脱落”,剩下的 8 位构成数字 94。

(是的,它是无害的)

【讨论】:

  • 顺便说一下,有符号字节(或其他有符号数字类型)也会发生非常相似的事情,除了有符号字节,只有 7 个“数据”位和一个符号位。这就是有符号字节为 127 + 1 = -128 的原因。 (符号字节变为 1 表示负数)
  • 这里有很多很棒的答案(每个人似乎对此都有一个非常清楚的了解,但我除外:)很难选择接受的答案,但我选择了这个。简短而好的解释。谢谢大家
  • 这在 C# 中是不正确的,给定的代码实际上不会编译。
  • @JeffYates - 告诉他为什么它不会编译并提供一些方法来解决他正在做的事情。要使其按原样编译: byte byte3 = (byte)(byte1 + byte2) 或使用 byte byte3 = (byte)byte1 + (byte)byte2 这些指令将编译并且可能会溢出 byte3 但有时对于单字节校验和值你不在乎。
【解决方案2】:

最高位将被截断。它对任何其他记忆都没有害处,它只会在意想不到的结果方面有害。

【讨论】:

    【解决方案3】:

    如果有的话,在 C# 中

     checked { byte byte3 = byte1 + byte2; }
    

    它会抛出一个溢出异常。代码默认编译为unchecked。正如其他答案所说,该值将“环绕”。即byte3 = (byte1 + byte2) & 0xFF;

    【讨论】:

    • 此代码无法编译。当你修复它时,真正的答案就变得显而易见了。
    • 哪个,示例或内联示例。拥有 3k+ 代表的人不能选择更正答案吗?
    • 这是不正确的,因为在加法中字节被提升为整数,从而导致整数。因此,如果没有强制转换,此代码将无法编译。
    【解决方案4】:

    进位标志被设置...但除了结果不是您所期望的之外,应该没有不良影响。

    【讨论】:

      【解决方案5】:

      通常(具体行为取决于语言和平台),结果将取模 256。即 150+199 = 349。349 mod 256 = 93。

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

        • byte 在 WinDef.h 中是 unsigned char。显然它可能是任何东西,但我认为我们正在被问及 Windows。
        • @steve:我是否另有说明?
        • @Armen:我在说你的虚张声势。是的,你做了,但后来你编辑了。
        • @Steve:我在发布答案后立即对其进行了编辑。然后在你的评论之后,这比我的编辑晚,我再次编辑以使单词字节格式化为byte。所以我想我们只是遇到了同步问题
        • @Armen:是的,发生了。如果我得到一页结果并花一分钟时间阅读它们,那么当我来评论时,我看到的答案可能已经过时了。评论不会重新加载页面,只是做一个 AJAX 的事情,所以我看到的内容可能会过时很长一段时间......
        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          行为取决于语言。

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

          在 C# 中,您可以使用 checked 关键字明确表示您希望在发生溢出时接收异常,并使用 unchecked 关键字明确表示您希望忽略它。

          【讨论】:

            【解决方案9】:

            前导刚刚掉线。

            【讨论】:

              【解决方案10】:

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

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

              【讨论】:

                【解决方案11】:

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

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

                【讨论】:

                • 所有这一切都表明发生了算术溢出 - 这一定是他们称你为 McWafflestix 的原因
                • @softwaremonkey:呵呵,好吧,问题是,这并不是真正的算术溢出;在执行操作的操作空间中,没有溢出,没有问题。了解这些事情以它们的方式发生是很有用的。另外,请注意,我最初是在谈论 C...
                【解决方案12】:

                就 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 节数字提升。

                【讨论】:

                  猜你喜欢
                  • 2016-09-17
                  • 2011-03-31
                  • 2017-09-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-02-24
                  • 2015-10-05
                  • 2021-04-09
                  • 2016-09-19
                  相关资源
                  最近更新 更多