目录
C语言有一个非常重要的特点就是非常灵活,而它的灵活就是体现在表达式的多样性。
最简单的表达式是由变量和常量组成的。变量表示程序运行时需要计算的值,常量表示不变的值,更加复杂的表达式便是把运算符用于操作数(操作数自身可以就是表达式)。在表达式a+(b*c)中,运算符+用于操作数a和(b*c),而这两者自身就是表达式。
运算符是构建表达式的基本工具,C语言拥有异常丰富的运算符,才使得C语言表达式的多样性。
运算符
算术运算符
一元运算符 | 二元运算符 | |
加法类 | 乘法类 | |
+ 一元正号运算符 | + 加法运算符 | * 乘法运算符 |
- 一元负号运算符 | - 减法运算符 | / 除法运算符 |
% 求余运算符 |
注:一二元指的是运算中所需要的操作数的个数
特别注意:除%运算符之外,上图中二元运算符既允许操作数是整数也允许操作数是浮点数,两者混合也是可以的。当int型操作数和float型操作数混合在一起时,运算结果为float型的。因此,9+2.5f的值为11.5.
运算符 / 和运算符%需要特别注意以下几点:
- 运算符 / 可能产生意外的结果。当两个操作数都是整数时,运算符 / 会丢掉分数部分来“截取”结果。因此,1/2 的结果为0 而不是0.5。
- 运算符%要求操作数必须是整数。如果两个操作数中有一个不是整数,程序将无法编译通过。
- 把0用作 / 或 % 的右操作数会导致未定义的行为。
- 当运算符/和运算符%用于负操作符时,其结果难以确定。根据 C89 标准,如果两个操作数中有一个为负数,那么除法的结果既可以向上舍人也可以向下舍人。(例如,-9/7 的结果既可以是-1 也可以是-2。)在 C89中,如果 i 或者 j 是负数,i%j 的符号与具体实现有关。 (例如,-9%7 的值可能是-2 或者 5。), 但是在 C99中,除法的结果总是趋零截尾的(因此-9/7 的结果是-1) i 的值的符号与的相同 (因此-9%7 的值是-2 )。
最高优先级 | + | - | (一元运算符) |
* | / | % | |
最低优先级 | + | - | (二元运算符) |
注:二元运算符是左结合的运算符,即在表达式包含两个或更多相同优先级的运算符时,运算符执行顺序为从左向右。例如:i - j - k 等价于 (i-j)-k
一元运算符为右结合,多个相同优先级运算符,从右向左执行。 -+i等价于 -(+i)
赋值运算符
求出表达式的值以后,通常需要将其存储到变量中,以便将来使用。C语言的 =(简单赋值)运算符可以用于此目的。为了更新已经存储在变量中的值,C语言还提供了一种复合赋值运算符。
复合运算符 | +=、-=、*=、/=、%=、&=、^=、 |=、>>=、<<= |
例如:v+=e表示v加上e,然后将结果存储到v中,以此类推......
注意:这里没有说v+= e“等价于”v=v+e。问题在于运算符的优先级:表达式i*=j+k和表达式i = i *j+ k是不一样的。在极少数情况下,由于v自身的副作用,v +=e也不等同于 v= v+e。类似的说明也适用于其他复合赋值运算符。
复合赋值运算符和=运算符是一样的,均是右结合。
自增运算符和自减运算符
自增运算符 | ++ |
自减运算符 | -- |
++表示操作数+1 , --表示操作数-1,同时++和--运算符既可以作前缀也可以作后缀使用(++i,--i)
++i和i++时截然不同的,++i代表着“立即自增i”,而i++代表着“现在先用i的原始值,在下一条语句执行前再自增i”。
例如:
int i, k, j;
i= 1;
j= 2;
k = i++ + j++;
执行语句后,i、j、k的值分别为2、3、3。
注意:后缀++和后缀--比一元的正号和负号优先级高,而且这两个后缀都是左结合的。
前缀++和前缀--与一元的正号和负号优先级相同,而且这两个前缀都是右结合的。
一元运算符
这些就是C语言中所有的一元操作符,其中需要注意的是,C语言中,将0视为逻辑假,非0视为逻辑真。
逻辑运算符
符号 | 含义 |
! | 逻辑非 |
&& | 逻辑与 |
| | | 逻辑或 |
逻辑运算符的操作如下:
- 如果表达式的值为 0,那么!表达式的结果为 1;
- 如果表达式1和表达式2的值都是非零值,那么表达式 1&& 达式2的结果为1;
- 如果表达式或表达式2的值中任意一个是(或者两者都是)非零值,那么表达式1表达式2的结果为 1。
在所有其他情况下,这些运算符产生的结果都为 0。(0为假,1为真)
关系运算符
符号 | 含义 |
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
注:关系运算符的优先级低于算术运算符,且关系运算符都是左结合。
判定运算符
符号 | 含义 |
== | 等于 |
!= | 不等于 |
注:和关系运算符一样,判定运算符也是左结合,并产生0或1作为结果。但是,判定运算符的优先级低于关系运算符。
C语言运算符优先级与结合图表
先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- |
() | 圆括号 | (表达式)/函数名(形参表) | -- | ||
. | 成员选择(对象) | 对象.成员名 | -- | ||
-> | 成员选择(指针) | 对象指针->成员名 | -- | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 一元运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
-- | 自减运算符 | --变量名/变量名-- | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | -- | ||
sizeof | 长度运算符 | sizeof(表达式) | -- | ||
3 | / | 除 | 表达式/表达式 | 左到右 | 二元运算符 |
* | 乘 | 表达式*表达式 | |||
% | 余数(取模) | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 二元运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 二元运算符 |
>> | 右移 | 变量>>表达式 | |||
6 | > | 大于 | 表达式>表达式 | 左到右 | 二元运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 二元运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 二元运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 二元运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 二元运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 二元运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 二元运算符 |
13 | ?: | 表达式1? 表达式2: 表达式3 | 右到左 | 三元运算符 | |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- |
/= | 除后赋值 | 变量/=表达式 | -- | ||
*= | 乘后赋值 | 变量*=表达式 | -- | ||
%= | 取模后赋值 | 变量%=表达式 | -- | ||
+= | 加后赋值 | 变量+=表达式 | -- | ||
-= | 减后赋值 | 变量-=表达式 | -- | ||
<<= | 左移后赋值 | 变量<<=表达式 | -- | ||
>>= | 右移后赋值 | 变量>>=表达式 | -- | ||
&= | 按位与后赋值 | 变量&=表达式 | -- | ||
^= | 按位异或后赋值 | 变量^=表达式 | -- | ||
|= | 按位或后赋值 | 变量|=表达式 | -- | ||
15 | , | 表达式,表达式,… | 左到右 | -- |
说明:
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符