【问题标题】:Question about unsigned int in c [duplicate]关于c中无符号整数的问题[重复]
【发布时间】:2011-09-03 23:08:06
【问题描述】:

可能重复:
unsigned int and signed char comparison

int j = 10;
unsigned int i = 10;
if( j > -1 )
    printf("1\n");
else
    printf("2\n");
if( i > -1 )
    printf("3\n");
else
    printf("4\n");

输出是:

1
4

我已经追踪到程序集,比较类似:

cmp     dword ptr [ebp-10h],0FFFFFFFFh
...
cmp     dword ptr [ebp-14h],0FFFFFFFFh

但还是不明白为什么一个是真的,一个是假的。

IMO cpu 不知道dword ptr 是否已签名。

那么它在底层是如何工作的呢?

更新

任何人都可以在汇编级别解释它吗?

【问题讨论】:

  • OP 的问题与建议的副本不同。请不要关闭。
  • 这不应该被关闭。这个问题是关于 x86 汇编程序的。

标签: c x86 assembly unsigned


【解决方案1】:

在以下代码中:

if( i > -1 )
    printf("3\n");
else
    printf("4\n");

-1 转换为 unsigned int,这是最大的 unsigned int,明显大于 10。

在我的机器上,下面的代码

#include <stdio.h>
int main()
{
  unsigned int i = -1;
  printf("%u\n", i);
  return 0;
}

产量:4294967295

【讨论】:

  • 稍微扩展一下,当发生有符号/无符号比较时,两种类型总是转换为无符号。当这种转换发生时,位表示不会改变。虽然 C++ 标准中没有指定,但最常见的有符号整数表示是二进制补码,它基本上隐式地从无符号位表示中减去最大可能无符号值的一半。如果你启用它们,你的编译器应该警告你。
  • 这个问题被标记为 C。std::cout&lt;iostream&gt; 不是 C。
  • @Prasoon:这只是为了说明将 -1 转换为无符号值时会发生什么。更改为纯 C :)
  • 你能在汇编层面解释一下吗?
  • @kern: 抱歉,那个抽象级别还不是我的领域 :)
【解决方案2】:

当将无符号(即i)与有符号(即-1)进行比较时,编译器会将有符号值转换为无符号。

-1 转换为无符号会产生非常大的值,因此( i &gt; -1) 条件会产生错误。

[6.3.1.3/2] (C99)

否则,如果新类型是无符号的,则通过重复添加或转换值 比新类型可以表示的最大值减一 直到值在新类型的范围内。

【讨论】:

    【解决方案3】:

    正如其他答案所说,-1 正在转换为无符号整数。检查下面的跳转指令。一个应该是“ja”,另一个应该是“jg”:无符号和有符号跳转指令。

    【讨论】:

    • 您能详细说明jajg 的事情吗?
    • +1 这是解决 OP 关于 asm 的真正问题的唯一答案,以及 OP 忽略了重要的指令这一事实:跳转。
    • jajnc 相同 - 如果进位标志清零,则跳转。 jg 依赖进位、符号和/或溢出标志(我忘记了细节,但您可以自己查找或解决)来实现带符号的比较,这更复杂。
    • @kern:汇编命令“cmp”基本上同时进行有符号和无符号比较。有符号数(jg、jl、jge、jle)有一类跳转语句,无符号数(ja、jb、jae、jbe)有一类跳转语句。
    【解决方案4】:

    这是您的程序,其中包含所有隐式转换:

      int j;
      unsigned int i;
      j = 10;
      i = (unsigned int)10;
      if (j > -1) { printf("1\n"); }
      else { printf("2\n"); }
      if (i > (unsigned int)-1) { printf("3\n"); }
      else { printf("4\n"); }
    

    第一个比较是有符号整数的比较。第二个是无符号整数的比较。

    关于您问题的另一方面,汇编中确实只有一个比较指令,但它设置了各种标志。您测试您感兴趣的标志以进行比较(有符号、无符号...)。

    【讨论】:

      【解决方案5】:

      在计算“>”运算符之前,两边的操作数需要(概念上)转换为相同的类型。在这种情况下(不确定它是“标准”还是编译器的突发奇想)-1 被转换为无符号。 -1 当然是 0xFFFFFFFF,在无符号比较中它比 0x0000000A 大,尽管在有符号比较中它更小(因为高位是符号位,而有符号负数几乎总是用“二进制补码”)。

      “幕后”我怀疑在你的 CPU 上生成的条件代码既有带符号的部分也有无符号的部分,两个结果之间的差异与条件代码的检查方式有关,而不是比较本身。

      【讨论】:

      • 这就是为什么在进行比较时将数字显式转换为所需形式而不是依赖隐式转换总是明智的。很难记住所有隐式转换规则并预测它们将如何应用。
      【解决方案6】:

      当您比较 unsigned int 和 signed int 时,signed int 将转换为 unsigned int。通过添加 UINT_MAX + 1 将负符号 int 转换为无符号 int。

      所以 -1 转换为 UINT_MAX + 1 - 1 = UINT_MAX 优于 10。

      另见What's the difference between the "unsigned preserving" and "value preserving" rules?

      【讨论】:

        【解决方案7】:

        正如@Neil G 指出的那样,虽然cmp 不知道无符号与有符号,但条件跳转指令知道。

        这样做是因为正常的算术指令(如sub)会影响所有相关的条件代码,因此您可以直接进行条件跳转,无需进行任何显式比较。

        请注意,cmp 只是一个sub,不会影响目的地。

        【讨论】:

          猜你喜欢
          • 2011-02-15
          • 2017-09-06
          • 1970-01-01
          • 2011-06-15
          • 2011-05-23
          • 1970-01-01
          • 2013-02-26
          • 1970-01-01
          • 2012-07-31
          相关资源
          最近更新 更多