unsigned和int gotcha

时间:2012-04-20 04:42:50

标签: c types type-conversion

  

可能重复:
  Arithmetic operations on unsigned and signed integers

unsigned int b=2;
int a=-2;

if(a>b)
    printf("a>b");
else
    printf("b>a");

输出:a> b

int b=2;
int a=-2;

if(a>b)
    printf("a>b");
else
    printf("b>a");

输出:b> a

请有人解释输出

5 个答案:

答案 0 :(得分:1)

在第一种情况下,两个操作数都转换为unsigned int,转换后的a将为UINT_MAX-1,它比b 更大因此输出。

除非您了解arithematic转换的语义,否则不要比较有符号和无符号整数,结果可能会让您感到惊讶。

答案 1 :(得分:0)

以下摘自The C Programming Language KernighanRitchie - 2.7 Type Conversions - 第44页;该页面的后半部分详细解释了相同的场景。下面有一小部分供您参考。

当涉及unsigned个操作数时,转换规则很复杂。问题是signedunsigned值之间的比较取决于机器,因为它们取决于各种integer类型的大小。例如,假设int长16位,long为32位。然后是-1L < 1U,因为1Uint,会被提升为signed long。但是-1L > 1UL,因为-1L被提升为unsigned long,因此似乎是一个更大的正数。

答案 2 :(得分:0)

当比较有符号值和无符号值时,并且无符号值不能全部用有符号类型表示时,则带符号的操作数将提升为无符号。这是通过一个公式来完成的,该公式相当于对2-s补码位模式的重新解释。

好吧,负数有很多高位设置......

由于你的操作数都是相同的等级,所以只需比较无符号位模式。

所以-2用111111..110表示,比最大可能值小1,当解释为无符号时,它很容易击败2。

答案 3 :(得分:0)

您需要了解C中的运算符操作以及C提升和转换规则。它们在C标准中解释。一些摘录加上我的评论:

6.5.8关系运营商
语法
1关系表达式:
移位表达
关系表达&lt;移位表达
关系表达&gt;移位表达
relational-expression&lt; = shift-expression
relational-expression&gt; = shift-expression

<强>语义
3如果两个操作数都有算术类型,则通常的算术转换为 进行。

大多数操作员在实际操作(加法,乘法,比较等)之前包括这个“通常的算术转换”步骤。 - Alex

6.3.1.8常规算术转换

1许多期望算术类型操作数的运算符会导致转换并产生结果 以类似的方式输入类型。目的是确定操作数的通用实数类型 和结果。对于指定的操作数,将转换每个操作数,而不更改类型 域,对应的实类型是常见的实类型。除非 另外明确说明,常见的真实类型也是相应的实际类型 结果,其类型域是操作数的类型域,如果它们是相同的, 否则复杂。这种模式称为通常的算术转换:

  • 首先,如果任一操作数的相应实数类型是long double,则另一个 操作数在不更改类型域的情况下转换为其类型的类型 相应的实际类型是长双。

  • 否则,如果任一操作数的相应实数类型为double,则为另一个 操作数在不更改类型域的情况下转换为其类型的类型 相应的实际类型是双倍。

  • 否则,如果任一操作数的相应实数类型为float,则为另一个 操作数在不更改类型域的情况下转换为其类型的类型 相应的真实类型是浮动。

  • 否则,将对两个操作数执行整数提升。那么 以下规则适用于提升的操作数:

  • 如果两个操作数具有相同的类型,则无需进一步转换。

  • 否则,如果两个操作数都有有符号整数类型或两者都有无符号 整数类型,具有较小整数转换等级类型的操作数是 转换为具有更高等级的操作数的类型。

  • 否则,如果具有无符号整数类型的操作数的等级大于或等于 等于另一个操作数的类型的等级,然后是操作数 有符号整数类型转换为带有unsigned的操作数的类型 整数类型。

  • 否则,如果带有符号整数类型的操作数的类型可以表示 那么,带有无符号整数类型的操作数类型的所有值 具有无符号整数类型的操作数将转换为该类型 带有符号整数类型的操作数。

  • 否则,两个操作数都将转换为无符号整数类型 对应于带有符号整数类型的操作数的类型。

6.3.1.3有符号和无符号整数

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

  2. 否则,如果新类型是无符号的,则通过重复添加或转换该值 减去一个可以在新类型中表示的最大值 直到该值在新类型的范围内。 (规则描述了数学值的算术,而不是给定类型表达式的值。)

  3. 否则,新类型已签名且值无法在其中表示;无论是 结果是实现定义的或引发实现定义的信号。

  4. 因此,在a>baintbunsigned int)中,根据上述规则,您获得{{1}在比较之前转换为a。由于unsigned int为负(-2),因此无符号值变为a(这是UINT_MAX+1+a位)。在您的情况下,repeatedly adding or subtracting one more than the maximum valueUINT_MAX+1+a = UINT_MAX+1-2,与UINT_MAX-1(2)的值相比,这是一个巨大的正数。所以b会产生“真实”。

    忘掉你在学校学到的数学知识。了解C是如何做到的。

答案 4 :(得分:-2)

在第一种情况下,您将unsigned转换为signed int。然后将这两者进行比较。

有符号和无符号类型之间的类型转换等级在C99中可以具有相同的等级。这是无符号和有符号类型具有相应类型的情况,当发生这种情况时,结果取决于编译器。

Here is a summary of the rules