【问题标题】:The real difference between "int" and "unsigned int"“int”和“unsigned int”之间的真正区别
【发布时间】:2012-02-21 03:48:51
【问题描述】:

int

32 位 int 数据类型可以保存范围为 -2,147,483,648 至 2,147,483,647。您也可以参考此数据类型 作为signed int 或signed。

无符号整数

32 位无符号整数数据 type 可以保存 0 到 4,294,967,295 范围内的整数值。你 也可以将此数据类型简称为无符号。

好的,但是,在实践中:

int x = 0xFFFFFFFF;
unsigned int y = 0xFFFFFFFF;
printf("%d, %d, %u, %u", x, y, x, y);
// -1, -1, 4294967295, 4294967295

没有区别,O.o.我有点困惑。

【问题讨论】:

标签: c


【解决方案1】:

呵呵。你在这里有一个隐式转换,因为你告诉printf 期望什么类型。

试试这个尺寸:

unsigned int x = 0xFFFFFFFF;
int y = 0xFFFFFFFF;

if (x < 0)
    printf("one\n");
else
    printf("two\n");
if (y < 0)
    printf("three\n");
else
    printf("four\n");

【讨论】:

    【解决方案2】:

    是的,因为在您的情况下,他们使用the same representation

    位模式0xFFFFFFFF 在解释为 32b 有符号整数时恰好看起来像 -1,而在解释为 32b 无符号整数时恰好看起来像 4294967295。

    char c = 65 相同。如果将其解释为有符号整数,则为 65。如果将其解释为字符,则为 a


    正如 R 和 pmg 指出的那样,从技术上讲,传递与格式说明符不匹配的参数是未定义的行为。所以程序可以做任何事情(从打印随机值到崩溃,再到打印“正确”的东西等等)。

    标准在7.19.6.1-9中指出

    如果转换规范无效,则行为未定义。 如果 任何参数都不是对应转换的正确类型 规范,行为未定义。

    【讨论】:

    • 真正的原因是他使用 %u 来打印两者。
    • 真正的原因是他通过将非类型匹配的格式字符串传递给printf调用未定义的行为。我几乎想对所有跳过这个并指出与表示无关的东西的答案投反对票......
    • @R.. 没错,格式和参数不匹配是未定义的行为。随意投反对票,我不介意:-)
    • @R..:你错了,这不是未定义的行为。请参阅 C99 第 6.5.2.2 节第 6 段。
    • @cha0site 不,他是对的,请阅读我更新的答案(特别是草稿中的引用)。
    【解决方案3】:

    两者在内存和寄存器中的存储方式没有区别,int 寄存器没有带符号和无符号版本,int 没有存储带符号的信息,只有在执行数学运算时才会产生差异,有签名和未签名版本的数学运算内置在 CPU 中,签名告诉编译器使用哪个版本。

    【讨论】:

    • 这个答案最简单
    【解决方案4】:

    问题是你调用了Undefined Behaviour


    当您调用 UB 时,任何事情都可能发生。

    作业没问题;第一行有一个隐式转换

    int x = 0xFFFFFFFF;
    unsigned int y = 0xFFFFFFFF;
    

    但是,调用printf 不行

    printf("%d, %d, %u, %u", x, y, x, y);
    

    % 说明符和参数类型不匹配是 UB
    在您的情况下,您通过提供 1 int、1 unsigned int、1 int 和 1 unsigned int,按此顺序指定 2 ints 和 2 unsigned ints。


    不要做UB

    【讨论】:

    • -1,错误。这不是未定义的行为。查看 C99 第 6.5.2.2 节第 6 段。
    • @cha0site:我特别说作业没问题:第 6.5.2.2 节第 6 段 并不真正适用于我的答案。 UB 在printf 调用中:检查7.19.6.1:“如果任何参数不是相应转换规范的正确类型,则行为未定义”。另请注意printf 是一个带有可变数量参数的函数,并且无法根据原型进行转换。
    • C99 6.5.2.2 优先于此。正在进行整数促销。我可能记错了——可能是第 5 段。
    • @cha0site 不,它没有。当函数采用可变数量的参数时,参数不能被提升为任何东西。
    • @cnicutar:什么?他们当然可以。那正是它所说的:“如果函数是用不包含原型的类型定义的,并且提升后的参数类型与提升后的参数类型不兼容,则行为未定义,除了以下情况:一种提升类型是有符号整数类型,另一种提升类型是对应的无符号整数类型,并且值可以在两种类型中表示;"
    【解决方案5】:

    intunsigned int的内部表示是一样的。

    因此,当您将相同的格式字符串传递给printf 时,它将被打印为相同。

    但是,比较它们时会有所不同。 考虑:

    int x = 0x7FFFFFFF;
    int y = 0xFFFFFFFF;
    x < y // false
    x > y // true
    (unsigned int) x < (unsigned int y) // true
    (unsigned int) x > (unsigned int y) // false
    

    这也是一个警告,因为在比较有符号和无符号整数时,其中之一将被隐式转换以匹配类型。

    【讨论】:

      【解决方案6】:

      他在问真正的区别。 当您谈论未定义的行为时,您处于语言规范提供的保证级别 - 这与现实相去甚远。 要了解真正的区别,请检查这个 sn-p(当然这是 UB,但它在您最喜欢的编译器上完美定义):

      #include <stdio.h>
      
      int main()
      {
          int i1 = ~0;
          int i2 = i1 >> 1;
          unsigned u1 = ~0;
          unsigned u2 = u1 >> 1;
          printf("int         : %X -> %X\n", i1, i2);
          printf("unsigned int: %X -> %X\n", u1, u2);
      }
      

      【讨论】:

        【解决方案7】:

        类型只是告诉你位模式应该代表什么。这些位只是您对它们的组成。相同的序列可以用不同的方式解释。

        【讨论】:

          【解决方案8】:

          printf 函数解释您根据匹配位置的格式说明符传递给它的值。如果您告诉 printf 您传递了 int,但传递了 unsignedprintf 会将其中一个重新解释为另一个,并打印您看到的结果。

          【讨论】:

            【解决方案9】:

            二进制表示是关键。一个例子: 十六进制的无符号整数

             0XFFFFFFF = translates to = 1111 1111 1111 1111 1111 1111 1111 1111 
            

            以十进制正数表示4,294,967,295。 但我们还需要一种表示负数的方法。 所以大脑决定使用二进制补码。 简而言之,他们取了最左边的位,并决定当它为 1 时(随后至少有一个其他位设置为 1),该数字将为负数。 并且最左边的位设置为0,该数字为正数。 现在让我们看看会发生什么

            0000 0000 0000 0000 0000 0000 0000 0011 = 3
            

            加上我们最终达到的数字。

            0111 1111 1111 1111 1111 1111 1111 1111 = 2,147,483,645
            

            带符号整数的最大正数。 让我们再添加 1 位(二进制加法会将溢出带到左边,在这种情况下,所有位都设置为 1,所以我们落在最左边的位)

            1111 1111 1111 1111 1111 1111 1111 1111 = -1
            

            所以我想简而言之,我们可以说不同之处在于一个允许负数,另一个不允许。 因为符号位或最左边位或最高有效位。

            【讨论】:

              猜你喜欢
              • 2017-06-20
              • 1970-01-01
              • 2013-11-12
              • 1970-01-01
              • 2017-09-10
              • 1970-01-01
              • 2011-12-12
              • 1970-01-01
              • 2011-08-06
              相关资源
              最近更新 更多