目录
前言
表达式求值的顺序一部分是由操作符的优先级和结合性决定的。
同样,有些表达式的操作数在求值的过程中可能需要转换成其他类型。
隐式类型转换
整型提升
c语言的整型算术运算总是至少以缺省整型的精度来运行的,所以表达式中的字符和短整型操作数要在使用前被转化为普通整型,这个过程叫做整型提升。
整型提升的原因可以简单理解为:CPU整型运算器的操作数字节长度一般就是4个字节,CPU很难直接对两个8比特的操作数进行运算。
整型提升规则
整型提升是按照变量类型的符号位来进行提升的
负数的整型提升
正数的整型提升
无符号整型提升
高位补0
整型提升的例子
例1:
分析:
例2:
分析:
a,b都要进行整型提升,而且a,b的符号位都是1,提升后都是负数,判断条件都为假,不打印。只有c被打印。
例3;
分析;
+和-都是单目操作符,它们的操作数都要整型提升,提升后大小为4字节。
算术转换
如果操作符的各个操作数是不同类型的,那么必须将一个操作数转化为另一个操作数的类型才能进行操作。下面的层次体系为寻常算数转换。
如果某个操作数在上表中的排名较低,就需要转换为另一个操作数的类型后执行运算。
总结:就高不就低
操作符的属性
复杂表达式的求值的影响因素:
1 操作符的优先级
2 操作符的结合性
3 是否控制求值顺序
两个相邻操作符先执行哪个,取决于它们的优先级;优先级相同,取决于它们的结合性。
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | ----- |
() | 圆括号 | (表达式)/函数名(形参表) | ----- | ||
. | 成员选择(对象) | 对象.成员名 | ----- | ||
-> | 成员选择(指针) | 对象指针->成员名 | ----- | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
(类型) | 强制类型转换 | (数据类型)表达式 | ----- | ||
++ | 前置自增运算符 | ++变量名 | 单目运算符 | ||
++ | 后置自增运算符 | 变量名++ | 单目运算符 | ||
-- | 前置自减运算符 | --变量名 | 单目运算符 | ||
-- | 后置自减运算符 | 变量名-- | 单目运算符 [4] | ||
* | 取值运算符 | *指针变量 | 单目运算符 | ||
& | 取地址运算符 | &变量名 | 单目运算符 | ||
! | 逻辑非运算符 | !表达式 | 单目运算符 | ||
~ | 按位取反运算符 | ~表达式 | 单目运算符 | ||
sizeof | 长度运算符 | sizeof(表达式) | ----- | ||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | 双目运算符 | ||
% | 余数(取模) | 整型表达式/整型表达式 | 双目运算符 | ||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | 双目运算符 | ||
5 | << | 左移 | 变量 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | 双目运算符 | ||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | 双目运算符 | ||
< | 小于 | 表达式 | 双目运算符 | ||
<= | 小于等于 | 表达式 | 双目运算符 | ||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | 双目运算符 | ||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | ----- |
/= | 除后赋值 | 变量/=表达式 | ----- | ||
*= | 乘后赋值 | 变量*=表达式 | ----- | ||
%= | 取模后赋值 | 变量%=表达式 | ----- | ||
+= | 加后赋值 | 变量+=表达式 | ----- | ||
-= | 减后赋值 | 变量-=表达式 | ----- | ||
<<= | 左移后赋值 | 变量 | ----- | ||
>>= | 右移后赋值 | 变量>>=表达式 | ----- | ||
&= | 按位与后赋值 | 变量&=表达式 | ----- | ||
^= | 按位异或后赋值 | 变量^=表达式 | ----- | ||
|= | 按位或后赋值 | 变量|=表达式 | ----- | ||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | 从左向右顺序运算 |
我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题
的。
例1:
a*b + c*d + e*f
我们只能确定*比+运算早,但是不能确定第三个*和第一个+谁先执行。如果abcdef都只是一个整数,结果不影响,但是如果它们都是一个表达式,而且它们的值会因为计算顺序而相互影响,那么结果在不同的编译器会大有不同。
例2:
c + --c
同样我们只能确定--在+之前,但是+的左操作数的值是在右操作数计算后获取还是之前获取未知,结果就不可预测。
例3:
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}
不少的学校会出这样的迷惑试题为难考生,其实本来就是错误代码。