0

可能重复:
无符号和有符号整数的算术运算

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

请有人解释一下输出

4

5 回答 5

1

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

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

于 2012-04-20T04:48:25.610 回答
0

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

6.5.8 关系运算符
语法
1 关系表达式:
shift-expression
关系表达式 < shift-expression
关系表达式 > shift-expression
关系表达式 <= shift-expression
关系表达式 >= shift-expression

语义
3 如果两个操作数都具有算术类型,则执行通常的算术转换。

大多数运算符在实际运算(加法、乘法、比较等)之前包括此“通常的算术转换”步骤。 - 亚历克斯

6.3.1.8 常用算术转换

1 许多期望算术类型的操作数的运算符会以类似的方式导致转换和产生结果类型。目的是确定操作数和结果的通用实数类型。对于指定的操作数,每个操作数都在不改变类型域的情况下转换为对应的实数类型是公共实数类型的类型。除非另有明确说明,否则公共实数类型也是结果的对应实数类型,如果操作数相同,则其类型域为操作数的类型域,否则为复数。这种模式称为通常的算术转换:

  • 首先,如果任一操作数的对应实数类型为 long double,则将另一个操作数转换为对应实数类型为 long double 的类型,而不改变类型域。

  • 否则,如果任一操作数的对应实数类型为双精度,则将另一操作数转换为对应实数类型为双精度的类型,而不改变类型域。

  • 否则,如果任一操作数的对应实数类型为浮点数,则将另一个操作数转换为对应实数类型为浮点数的类型,而不改变类型域。

  • 否则,对两个操作数都执行整数提升。然后将以下规则应用于提升的操作数:

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

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

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

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

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

6.3.1.3 有符号和无符号整数

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

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

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

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

忘记你在学校学过的数学。了解 C 是如何做到的。

于 2012-04-20T05:14:14.980 回答
0

以下内容摘自第 44 页和-第 44 页The C Programming Language;页面的后半部分详细解释了相同的场景。下面一小部分供大家参考。KernighanRitchie2.7 Type Conversions

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

于 2012-04-20T04:57:03.703 回答
0

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

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

由于您的操作数都是相同的等级,这只是比较无符号位模式的问题。

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

于 2012-04-20T05:06:13.573 回答
-2

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

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

这是规则的摘要

于 2012-04-20T04:58:43.070 回答