操作符详解
表达式求值
表达式求值的顺序一部分是由操作符的优先级和结核性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,称为整型提升。
整型提升的意义:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
//实例
char a, b, c;
a = b + c;
b和c的值被提升为普通整形,然后再执行加法运算。加法运算完成之后,结果将被截断,然后再储存于a中。
整型提升是按照变量的数据类型的符号位来提升的。
负数的整型提升,高位补充符号位1;
正数的整型提升,高位补充符号位0。
无符号整型提升,高位补0。
int main() {
char a = 3, b = 127;
char c = a + b;
//发现a和b都是char类型的,没有达到int大小
//00000011——a
//01111111——b
//整型提升
//00000000 00000000 00000000 00000011——a
//00000000 00000000 00000000 01111111——b
//00000000 00000000 00000000 10000010——c
//截断
//10000010——c
//11111111 11111111 11111111 10000010——c
//00000000 00000000 00000000 01111110——原码
printf("%d\n", c); //-126
return 0;
}
int main() {
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6) {
printf("a");
}
if (b == 0xb600) {
printf("b");
}
if (c == 0xb6000000) {
printf("c");
}
return 0;
}
a,b整型提升之后变成了负数,所以最后只输出c。
int main() {
char c = 1;
printf("%u\n", sizeof(c)); //1
printf("%u\n", sizeof(+c)); //4
printf("%u\n", sizeof(-c)); //4
return 0;
}
c只要参与表达式运算,就会发生整型提升。
算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算数转换。
如果某个操作数的类型在下表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
long double
double
float
unsighed long int
long int
unsighed int
int
//算术转换
int main() {
int a = 4;
float f = 4.5f;
a + f;
return 0;
}
//例
int i; //i是全局变量,不初始化,默认是0
int main() {
i--; //-1
//sizeof操作符算出的结果类型是unsigned int
if (i > sizeof(i)) { //i=-1的补码32个1被看作无符号数,是一个超级大的数,大于4
printf(">\n");
}
else {
printf("<\n");
}
return 0;
}
操作符的属性
复杂表达式的求值有三个影响因素:
1、操作符的优先级
2、操作符的结合性
3、是否控制求值顺序