#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&gt; y',但事实并非如此。编译器给出输出 - “x&lt; = y”。你能解释一下原因吗?
答案 0 :(得分:7)
在比较中,signed char
被转换为unsigned int
,因此看起来非常重要。我希望编译器能够警告你 - 也就是说“比较有符号和无符号的东西”这一点令人困惑。
此转换是在“关系运算符”下强制执行的:
如果两个操作数都有算术类型,那么通常 进行算术转换。
答案 1 :(得分:2)
C11§6.8al3p95:
如果两个操作数都有算术类型,则通常的算术转换是 进行。
C11§6.3.1.8al1p53:
[...]如果具有无符号整数类型的操作数的排名更高 或者等于另一个操作数的类型的等级,然后是 带有符号整数类型的操作数转换为 具有无符号整数类型的操作数。
因此,y
将被提升为无符号类型,并且将大于x
(1
)。
答案 2 :(得分:0)
相比之下,如果一个操作数是无符号的,那么如果其类型被签名,则另一个操作数被隐式转换为无符号!
在此处找到更多内容:Signed/unsigned comparisons
答案 3 :(得分:0)
在你的情况下,signed char被转换为unsigned int,因此我们得到一个大的正整数而不是-1。以下是ANSI C标准草案的摘录,解释了在通常的算术转换过程中发生的情况。
3.2.1.5常用算术转换
许多期望算术类操作数的二元运算符会导致 以类似的方式转换和生成结果类型。目的是 产生一个公共类型,这也是结果的类型。这个 模式称为通常的算术转换:首先,如果是 操作数的类型为long double,另一个操作数转换为long 双倍。否则,如果任一操作数的类型为double,则另一个 操作数转换为double。否则,如果任一操作数具有类型 float,另一个操作数转换为float。否则, 在两个操作数上执行整体促销。那么 应用以下规则:如果任一操作数的类型为unsigned long int,另一个操作数转换为unsigned long int。除此以外, 如果一个操作数的类型为long int而另一个操作数的类型为unsigned int, 如果long int可以表示unsigned int的所有值,那么操作数 unsigned int类型转换为long int;如果一个长int不能 表示无符号整数的所有值,两个操作数都是 转换为unsigned long int。否则,如果任一操作数具有类型 long int,另一个操作数转换为long int。 否则,如果任一操作数的类型为unsigned int,则另一个操作数将转换为unsigned int。否则,两个操作数都有 输入int。
答案 4 :(得分:0)
习惯于编译所有警告,例如gcc:
gcc -Wall -Wextra -pedantic source.c -o prog
在您的情况下,标志-Wextra
会给出以下消息:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
这不能解释原因,但它至少会警告你;)。
解释是,与关系运算符进行比较时,评估为-1
的带符号变量等于对UINT_MAX
的无符号求值。
编译器必须在这种情况下做一些很好的定义,这就是人们提出的......
答案 5 :(得分:0)
当编译器看到将unsigned int与signed int进行比较时,它将signed int提升为unsigned,这意味着将此(在linux框中)添加到已签名的int:
#define UINT_MAX (~0U) (defined in this header file : /include/linux/kernel.h)
所以现在你将 UINT_MAX - 1(UINT_MAX + y)与 x 进行比较,这清楚地解释了输出。
编辑:更清楚:在32位机器上---&gt; UINT_MAX = 2 147 483 648 = 2**31
问候。