请看我的测试代码:
#include <stdlib.h>
#include <stdio.h>
#define PRINT_COMPARE_RESULT(a, b) \
if (a > b) { \
printf( #a " > " #b "\n"); \
} \
else if (a < b) { \
printf( #a " < " #b "\n"); \
} \
else { \
printf( #a " = " #b "\n" ); \
}
int main()
{
signed int a = -1;
unsigned int b = 2;
signed short c = -1;
unsigned short d = 2;
PRINT_COMPARE_RESULT(a,b);
PRINT_COMPARE_RESULT(c,d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
a > b
c < d
Run Code Online (Sandbox Code Playgroud)
我的平台是Linux,我的gcc版本是4.4.2.我对输出的第二行感到惊讶.第一行输出是由整数提升引起的.但为什么第二行的结果不同?
以下规则来自C99标准:
如果两个操作数具有相同的类型,则不需要进一步转换.否则,如果两个操作数都具有有符号整数类型或两者都具有无符号整数类型,则具有较小整数转换等级类型的操作数将转换为具有更高等级的操作数的类型.
否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型.
否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为带有符号整数类型的操作数的类型.
否则,两个操作数都转换为无符号整数类型,对应于带有符号整数类型的操作数的类型.
我认为两个比较都应该属于同一个案例,第二个案例是整数提升.
Die*_*Epp 20
使用算术运算符时,操作数将进行两次转换.
整数提升:如果int可以表示该类型的所有值,则将操作数提升为int.这适用于大多数平台short和unsigned short大多数平台.在此阶段执行的转换分别在每个操作数上完成,而不考虑其他操作数.(有更多规则,但这是适用的规则.)
通常的算术转换:如果您将a unsigned int与a 进行比较signed int,因为既不包括另一个的整个范围,并且两者都具有相同的等级,则两者都会转换为该unsigned类型.在检查两个操作数的类型之后完成此转换.
显然,如果没有两个操作数,"通常的算术转换"并不总是适用.这就是为什么有两套规则.例如,一个问题是移位运算符<<并且>>不执行通常的算术转换,因为结果的类型应该仅取决于左操作数(因此,如果您看到某个类型x << 5U,则U表示"不必要").
细分:假设一个典型的系统具有32位int和16位short.
int a = -1; // "signed" is implied
unsigned b = 2; // "int" is implied
if (a < b)
puts("a < b"); // not printed
else
puts("a >= b"); // printed
Run Code Online (Sandbox Code Playgroud)
int或者unsigned int没有促销.int不能代表所有可能的值unsigned,并且unsigned不能代表所有可能的值int,因此没有明显的选择.在这种情况下,两者都转换为unsigned.if (4294967295u < 2u)虚假.现在让我们尝试一下short:
short c = -1; // "signed" is implied
unsigned short d = 2;
if (c < d)
puts("c < d"); // printed
else
puts("c >= d"); // not printed
Run Code Online (Sandbox Code Playgroud)
int,所以两者都被提升为int.int,所以什么都没做.if (-1 < 2)现实.编写好的代码:有一种简单的方法可以在代码中捕获这些"陷阱".只需编译并打开警告,并修复警告.我倾向于编写这样的代码:
int x = ...;
unsigned y = ...;
if (x < 0 || (unsigned) x < y)
...;
Run Code Online (Sandbox Code Playgroud)
您必须注意,您编写的任何代码都不会遇到其他已签名和未签名的陷阱:签名溢出.例如,以下代码:
int x = ..., y = ...;
if (x + 100 < y + 100)
...;
unsigned a = ..., b = ...;
if (a + 100 < b + 100)
...;
Run Code Online (Sandbox Code Playgroud)
一些流行的编译器将优化(x + 100 < y + 100)到(x < y),但这是另一天的故事.只是不要溢出你签名的号码.
附注:请注意,虽然
signed是隐含的int,short,long,和long long,这是不是暗示了char.相反,它取决于平台.