#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”。你能解释为什么吗?为什么输出错误?
#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
,因此看起来像一个非常大的价值。我希望编译器能够警告你 - 例如,“比较已签名和未签名的东西是令人困惑的”。
这种转换是根据“关系运算符”规定:
如果两个操作数的算术具有类型,通常的 算术转换被执行。
作为比较,如果一个操作数是无符号的,则另一个操作数如果其类型被签名,则隐式转换为无符号!
更多地在这里找到:Signed/unsigned comparisons
在你的情况有符号的字符转换为unsigned int类型,所以我们得到一个大的正整数,而不是-1。这里是ANSI C标准草案的一个摘录,它解释了在发生常规算术转换期间发生的事情。
3.2.1.5常见的算术转换
许多双目操作符,期待 转化和产量的结果类型以类似的方式的算术类型原因操作数。目的是产生一个通用的类型,这也是结果的类型,即 。这种 模式被称为通常的算术转换:首先,如果任一 操作数的类型为long double,则另一个操作数转换为长整数 double。否则,如果任一操作数的类型为double,则另一个操作数将转换为double。否则,如果任一操作数的类型为 float,则另一个操作数转换为float。否则, 积分促销在两个操作数上执行。然后 应用下列规则:如果任一操作数的类型无符号长 int,则另一个操作数转换为unsigned long int类型。否则,如果 一个操作数的类型长int和另一个具有unsigned int类型, 如果一个长整型可以表示一个unsigned int的所有值,操作数 类型的无符号整型转换为长整型;如果long int不能 表示无符号整型的所有值,则两个操作数都是 转换为unsigned long int。否则,如果任一操作数的类型为 long int,则另一个操作数将转换为long int。 否则,如果任一操作数的类型为unsigned int,则另一个操作数转换为unsigned int。否则,两个操作数都有 int类型。
C11§6.8AL3 P95:
如果两个操作数的算术具有类型,通常的算术转换为执行 。
C11§6.3.1.8AL1的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
。
编译器必须做在这种情况下,明确的东西,这就是人们想出了...
当编译器看到有符号整数它促进符号int无符号比较一个unsigned int,这意味着要添加这个(在Linux机器)已签署的一个:
#define UINT_MAX (~0U) (defined in this header file : /include/linux/kernel.h)
所以,现在你是比较UINT_MAX - 与X,这清楚地解释输出1(UINT_MAX + Y)。
编辑:更加清楚:在32位机器--->UINT_MAX = 2 147 483 648 = 2**31
问候。
对不起,编译器不警告。它只是给出了提到的输出。我正在使用Codeblocks编译器。谢谢您的回答。 – Niteesh 2012-07-29 12:34:44