1. 表达式定义
C语言中的表达式是一种有值的语法结构,它由运算符(变量,常量,函数调用返回值)结合而成,每个表达式一定有一个值
常量表达式
比如 a,12,12.4 值就是变量或者常量本身的值,作为条件的时候,非零为真,零值为假
算术表达式
a+b c*d+a 12/3+d i++ –a 值就是表达式的结果
赋值表达式
a=12 a+=12 a = c = d 表示对 a 变量进行赋值
关系表达式
a > b 2 ==3 值可以认为是布尔值,由于C语言中没有bool 值,用整型值 0 和 1 表示
逻辑表达式
a && b c || d !a 值可以认为是布尔值,由于C语言中没有bool 值,用整型值 0 和 1 表示
复合表达式
x = ( y = (a + b + a > 4), z=10) 依据运算符优先级和结合性得到结果
逗号表达式
(1,2,3,4,a) 从左到右依次求值,表达式的值是逗号最右边的值
有返回值的函数
有返回值的函数也是一个表达式
2. 表达式求值
整型提升
C语言的整数算术运算至少是以缺省的整型类型的精度进行的,为了获得这个精度,表达式中字符型和短整型在使用之前转换为普通整型,这种转换称为整型提升
char a,b,c;
a = b + c
b 和 c 的值被提升为普通整型,然后再执行加法运算,加法运算的结果被截短,然后再存储于 a 中
隐式类型转换
C语言在下面几种情况下进行隐式类型转换:
- 算术表达式中,低类型会转换为高类型
- 赋值表达式中,右侧表达式的值可以自动转换为左侧变量的类型,赋值给它
- 函数调用中参数传递时,系统隐式将实参转换为形参的类型后,赋值给形参
- 函数有返回值时,系统隐式将返回表达式类型转换为返回值类型,并赋值给调用函数
表达式求值中的自动类型转换
下面层次体系称为寻常算术转换:
转换规则:
- 如果某个操作数类型在上面列表中排名较低,那么首先将其转换为另一个操作数的类型然后再执行操作
- 转换按照数据长度增加的方向进行,以保证精度不降低,比如 int 型和 long 型运算时,先把int 类型转换为 long 型后再进行计算
- 若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
- 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算
- char 和 short 类型参与运算时,必须先转换为 int 类型(整形提升)
注意float 类型转换为整型值的时候,小数部分会被舍弃(并不进行四舍五入)
static void _floatconvert() {float m = 3.14f;int n = m;printf("the value of n = %d \n", n);}
3. 操作符的属性
复杂表达式的求值顺序是由三个因素决定的,操作符的优先级,操作符的结合性以及操作符是否控制执行顺序。
两个相邻的操作符哪个先执行取决于它们的优先级,如果两者优先级相同,那么执行顺序由它们的结合性决定
简单来说,结合性就是一串操作符是从到右依次执行还是从右到左依次执行
- 初级运算符总共有四个下标访问操作符[ ],括号操作符(),访问结构成员 .,访问结构指针成员 ->,
- 算术运算符先乘除后加减
- 关系运算符中先大小后相等(关系运算符中 > = <= 的优先级高于 == 和 ! =)
- 位运算分为四个等级,取反(等级最高是单目运算符),与,异或,或
- 逻辑运算符分为三个等级,逻辑非(等级最高是单目运算符),逻辑与,逻辑或
运算符中只有三类是从右到左,其余都是从左到右
赋值,条件(?:)和单目运算符 这三类运算符的结合方式是从右到左,其余都是从左到右
常见的优先级问题:
- 结构体成员访问运算符的优先级高于间接访问 *p.f 等同于*(p.f),使用访问结构体成员运算符
p -> f 可以避免这个问题
- 下标访问运算符优先级高于间接访问 int *ap[ ],表示的是一个指针数组
- 函数调用优先级高于间接访问,int *p(),表示返回值是指针的函数 p
- == 和 != 优先级高于位操作 value & value != 2 等同于value & (value != 2)
- == 和 != 优先级高于赋值运算符,c = getchar() != EOF 等同于c = (getchar() != EOF)
- 算术运算符优先级高于位移运算符,msb << 4 + lsb 等同于msb << (4 + lsb)
- 逗号运算符的优先级最低
- 间接访问运算符优先级高于算术运算符,*p + 1 表示的是 间接访问 p 的值加1,*(p + 1)表示的是访问 p 指向元素连续内存的下一个元素
void _testOperatorPriority() {int array[] = { 10, 20, 30, 40 };int *p = array;//11printf("*p + 1 = %d \n", *p + 1);// 20printf("*(p + 1) = %d \n", *(p + 1));// *p++printf("*p++ = %d %d %d\n", *p++, *p++, *p++);}