【问题标题】:What will happen if I assign negative value to an unsigned char?如果我为 unsigned char 分配负值会发生什么?
【发布时间】:2017-05-07 17:00:40
【问题描述】:

在 C++ 入门中它说“如果我们为无符号类型的对象分配一个超出范围的值,则结果是该值的余数模目标类型可以容纳的值的数量。”

举个例子:

int main(){


unsigned char i = -1;
// As per the book the value of i is 255 .
}

任何人都可以向我解释一下这是如何工作的。

【问题讨论】:

    标签: c c++11 unsigned


    【解决方案1】:

    结果是取模目标类型可以容纳的值的数量的余数

    从“目标类型可以容纳的值的数量”开始。对于unsigned char,这是什么?范围是从 0 到 255,包括 0 到 255,因此总共有 256 个值可以表示(或“保持”)。

    一般来说,可以用特定的无符号整数表示的值的数量由 2n 给出,其中 n 是用于存储的位数那种类型。

    unsigned char 是 8 位类型,所以 28 == 256,正如我们已经知道的那样。

    现在,我们需要执行 模 运算。在您将 -1 分配给 unsigned char 的情况下,您将拥有 -1 MOD 256 == 255。

    一般来说,公式是:x MOD 2n,其中 x 是您尝试分配的值,n 是您尝试分配的类型的位宽。

    更正式地说,这是在 C++11 语言标准(第 3.9.1/4 节)中规定的。它说:

    声明为无符号的无符号整数应遵守算术模 2n 的定律,其中 n 是该特定整数大小的值表示中的位数。 *

    * 这意味着无符号算术不会溢出,因为无法由生成的无符号整数类型表示的结果以比可以表示的最大值大一的数字为模减少得到的无符号整数类型。

    也许考虑模运算(以及您最常看到使用的描述)的更简单方法是上溢和下溢环绕。您从 -1 开始,它下溢了 unsigned char 的范围(即 0–255),因此它环绕到最大可表示值(即 255)。

    【讨论】:

    • 但是当我尝试 -1 % 256 它给了我 -1 时,我无法获得 255 作为我的代码输出。
    • "你从 -1 开始,它下溢了 unsigned char 的范围(0-255),所以它环绕到最大可表示值(255)。"
    • 整数字面量默认为int 类型,小于int 的类型在用于表达式时提升为int。因此,表达式-1 % 256 将给出一个int 的结果。 -1 可以表示为int,所以它就是答案。这与您的问题完全不同,后者将 -1 的值存储在 unsigned char 类型中。
    • 好的,这是因为给出的值是 255,但我无法理解这是如何发生的,即为什么我询问 -1 %256。
    • 哦,我明白你的困惑了。您正尝试在 C++ 中执行此代码,但其中的 % 运算符不完全是模数 - 它是 remainder,并且语义略有不同。如果第一个参数为负数,则返回负数。您需要逻辑算术模运算。
    【解决方案2】:

    它在 C 中等同于 C++,但措辞不同:

    6.3.1.3 有符号和无符号整数

    1当一个整数类型的值被转换为除_Bool以外的其他整数类型时,如果该值可以用新的类型表示,则保持不变。

    2否则,如果新类型是无符号的,则在新类型所能表示的最大值的基础上反复加减一,直到值在新类型的范围内。

    p>

    3 否则,新类型是有符号的,值不能在其中表示;结果要么是实现定义的,要么引发实现定义的信号。

    【讨论】:

      【解决方案3】:

      文字1 是int 类型。对于这个解释,我们假设sizeof(int) == 4 很可能是这样。那么二进制中的1 看起来像这样:

      00000000 00000000 00000000 00000001 
      

      现在让我们应用一元减号运算符来获得-1。我们假设 two 的补码 被使用,因为它很可能是(查找二的补码以获得更多解释)。我们得到:

      11111111 11111111 11111111 11111111
      

      请注意,在上面的数字中,第一位是符号位。

      当您尝试将此数字分配给 unsigned char(其中包含 sizeof(unsigned char) == 1)时,该值将被截断为:

      11111111
      

      现在如果你把它转换成十进制,你会得到255。这里第一位不被视为符号位,因为类型是unsigned。

      【讨论】:

      • 使用11111111 11111111 11111111 11111111 以外的位模式会更清楚11111111 的来源。
      • 这是错误的。有符号整数类型的表示不影响无符号类型的结果,它的值会影响。
      • @2501 如果编译器创建的代码会隐藏程序员的实际值,则需要使用不同的语言,只需创建一个用于处理直接建模对象的 API。那些试图提出其他建议的人,就像那种会拿一瓶装有柠檬酸和黄色油漆的水,并说这是柠檬汁,因为标签上写着,不管它是如何制作的。无论如何,当前标准的陈述都是基于现有平台上整数的实际表示,为了简短起见,它们只是以抽象数学方式解释
      • 我不是在吹毛求疵。你实际上错了。二进制补码中 -1 的表示形式是 11111111。 -1 在一个补码中的表示是11111110。将值 -1 转换为无符号整数的结果将始终给出最大可能的结果,其中所有位都已设置:11111111。使用你的方法会根据整数表示给出不同的结果,显然不是这样。
      【解决方案4】:

      用 Stroustrup 的话来说:

      如果目标类型是unsigned,则结果值只是来自源的位数与目标中的位数相同(必要时丢弃高位)。更准确地说,结果是与源整数模 2 到第 n 次一致的最小无符号整数,其中 n 是用于表示无符号类型的位数。

      摘自 C++ 标准 N3936:

      对于每个标准的有符号整数类型,都存在一个对应的(但不同的)标准无符号 整数类型:“unsigned char”、“unsigned short int”、“unsigned int”、“unsigned long int”、 和“unsigned long long int”,每个都占用相同的存储量并且具有相同的 对齐要求(3.11)作为相应的有符号整数类型47;也就是说,每个有符号整数类型 具有与其对应的无符号整数类型相同的对象表示。

      【讨论】:

        【解决方案5】:

        我自己正在阅读 C++ 入门的摘录,我认为我已经找到了一种数学方法来计算这些值是如何产生的(如果我错了,请随时纠正我 :))。以下面的特定代码为例。

        unsigned  char c = -4489;
        std::cout << +c << std::endl; // will yield 119 as its output
        

        那么这个119的答案是怎么出来的呢?

        取 4489 除以字符总数,即 2^8 = 256,余数为 137。

        4489 % 256 = 137。

        现在只需从 256 中减去 137。

        256 - 137 = 119。

        这就是我们简单地推导出 mod 值的方式。也请自己尝试其他价值观。对我来说非常准确!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-01
          • 2021-11-13
          • 1970-01-01
          • 2018-06-30
          相关资源
          最近更新 更多