#include<stdio.h>
main()
{
unsigned x=1;
signed char y=-1;
clrscr();
if(x>y)
printf("x>y");
else
printf("x<=y");
}
有符号字符的值从 -128 增加到 127。所以预期的输出应该是“x>y”,但事实并非如此。编译器给出输出 - “x<=y”。你能解释一下为什么吗?
在比较中,signed char
转换为一个unsigned int
,因此看起来像一个非常大的值。我希望编译器会警告您 - 即“比较有符号和无符号的东西令人困惑”中的某些内容。
这种转换是在“关系运算符”下强制执行的:
如果两个操作数都具有算术类型,则执行通常的算术转换。
C11 §6.8 al3 p95:
如果两个操作数都具有算术类型,则执行通常的算术转换。
C11 §6.3.1.8 al1 p53:
[...]如果具有无符号整数类型的操作数的等级大于或等于另一个操作数类型的等级,则具有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。
所以y
将被提升为无符号类型,并且将大于x
( 1
)。
习惯于编译所有警告,即在 gcc 的情况下:
gcc -Wall -Wextra -pedantic source.c -o prog
在您的情况下,该标志-Wextra
会给出以下消息:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
这并不能解释原因,但它至少会警告你 ;) 。
解释是当与关系运算符相比时,-1
评估为的有符号变量等于评估为的无符号变量。UINT_MAX
在这种情况下,编译器必须做一些明确定义的事情,这就是人们想出的......
当编译器看到将无符号整数与有符号整数进行比较时,它会将有符号整数提升为无符号整数,这意味着将这个(在 linux 框中)添加到有符号整数:
#define UINT_MAX (~0U) (defined in this header file : /include/linux/kernel.h)
因此,现在您将 UINT_MAX - 1 (UINT_MAX + y)与x进行比较,这清楚地解释了输出。
编辑:更清楚:在 32 位机器上--->UINT_MAX = 2 147 483 648 = 2**31
问候。
相比之下,如果一个操作数是无符号的,那么如果它的类型是有符号的,则另一个操作数会隐式转换为无符号!
更多可以在这里找到:有符号/无符号比较
在您的情况下,signed char 被转换为 unsigned int,因此我们得到一个大的正整数而不是 -1。这是 ANSI C 标准草案的摘录,它解释了在发生的通常算术转换过程中发生的情况。
3.2.1.5 常用算术转换
许多期望算术类型的操作数的二元运算符会导致转换并以类似的方式产生结果类型。目的是产生一个通用类型,这也是结果的类型。这种模式称为通常的算术转换:首先,如果任一操作数的类型为 long double ,则另一个操作数将转换为 long double 。否则,如果任一操作数的类型为 double,则另一个操作数将转换为 double。否则,如果任一操作数的类型为 float,则另一个操作数将转换为 float。否则,将对两个操作数执行整数提升。然后应用以下规则: 如果任一操作数的类型为 unsigned long int,则另一个操作数将转换为 unsigned long int。否则,如果一个操作数的类型为 long int,而另一个操作数的类型为 unsigned int,如果 long int 可以表示 unsigned int 的所有值,则 unsigned int 类型的操作数将转换为 long int ;如果 long int 不能表示 unsigned int 的所有值,则两个操作数都将转换为 unsigned long int。否则,如果任一操作数的类型为 long int,则另一个操作数将转换为 long int。 否则,如果任一操作数的类型为 unsigned int,则另一个操作数将转换为 unsigned int。 否则,两个操作数的类型都是 int。