1. 运算符优先级的定义
在C语言中,运算符优先级是由编译器按照一定规则预先定义的,用于确定运算符之间的执行优先级。在进行表达式运算时,编译器按照运算符优先级来确定运算符的执行顺序,从而获取正确的表达式运算结果。
下面是C语言中常用的运算符优先级从高到低的顺序表:
()
// 括号,强制优先级
! ~ ++ -- + -
// 一元运算符
* / %
// 乘、除、取余
+ -
// 加、减
<< >>
// 左移、右移
< <= > >=
// 小于、小于等于、大于、大于等于
== !=
// 等于、不等于
&
// 按位与
^
// 按位异或
|
// 按位或
&&
// 逻辑与
||
// 逻辑或
?:
// 条件运算符
= += -= *= /= %=
// 赋值运算符
,
// 逗号,用于分隔表达式
需要注意的是,优先级高的运算符并不一定比优先级低的运算符先执行,这还要考虑到运算符的结合性(左结合和右结合)。
2. 左结合和右结合
2.1 左结合
对于优先级相同的运算符,C语言默认采取左结合(left-associative)的方式来进行运算。
所谓左结合,就是指相同优先级的运算符从左往右执行。比如,对于如下的表达式:
int a = 1, b = 2, c = 3;
a + b + c;
因为加法运算符具有左结合性,所以会先计算a+b的值,再和c相加。相当于以下表达式:
(a+b)+c;
2.2 右结合
有些运算符,比如赋值运算符和三目运算符,采用的是右结合(right-associative)方式进行运算。
所谓右结合,就是指相同优先级的运算符从右往左执行。
以赋值运算符为例,如下的赋值语句:
int a = 5, b = 10, c = 20;
a = b = c;
因为赋值运算符的优先级比等于号要低,而且赋值运算符采用的是右结合,所以先执行b=c,再执行a=b,最终a、b、c的值都变成了20。
3. 运算符优先级示例
3.1 算术运算符的优先级
算术运算符包括加、减、乘、除、取余等运算符,其优先级从高到低为:
* / %
+ -
这意味着,乘、除、取余优先级高于加、减。下面的示例演示了算术运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3, c = 8;
int result = a + b * c;
printf("a + b * c = %d\n", result);
return 0;
}
这个例子中,由于乘法运算符的优先级高于加法运算符,所以先计算b*c的结果,然后再加上a的值,最终得到23。
3.2 逻辑运算符的优先级
逻辑运算符包括与、或、非等运算符,其优先级从高到低为:
!
&&
||
这意味着,非运算符的优先级高于与运算符,与运算符的优先级高于或运算符。下面的示例演示了逻辑运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3, c = 0;
int result = (a > b) && (c != 0);
printf("(a > b) && (c != 0) = %d\n", result);
return 0;
}
这个例子中,由于与运算符的优先级高于或运算符,所以先计算(a>b)的结果,再计算(c!=0)的结果,最后将它们用与运算符连接起来,得到结果0。
3.3 关系运算符的优先级
关系运算符包括小于、小于等于、大于、大于等于、等于和不等于等运算符,其优先级从高到低为:
< <= > >=
== !=
这意味着,小于、小于等于、大于、大于等于优先级高于等于和不等于。下面的示例演示了关系运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3, c = 8;
int result = (a > b) != (c < a);
printf("(a > b) != (c < a) = %d\n", result);
return 0;
}
这个例子中,由于小于运算符的优先级低于不等于运算符,所以先计算cb的结果,最后将它们用不等于运算符连接起来,得到结果1。
3.4 赋值运算符的优先级
C语言中的赋值运算符不仅仅是一个等于号,还可以和其他运算符组合形成不同的赋值运算。
赋值运算符的优先级是从右往左依次降低的。比如,先计算右边表达式的值,然后再把它赋值给左边的变量。
下面的表格列出了常见的赋值运算符及其组合形式,从上到下优先级依次降低:
赋值运算符 | 组合表达式 |
---|---|
= | x = 5 |
+= | x += 5 |
-= | x -= 5 |
*= | x *= 5 |
/= | x /= 5 |
%= | x %= 5 |
<<= | x <<= 2 |
>>= | x >>= 2 |
&= | x &= 5 |
^= | x ^= 5 |
|= | x |= 5 |
下面的示例演示了赋值运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3, c = 8;
a += b *= c %= 3;
printf("a = %d, b = %d, c = %d\n", a, b, c);
return 0;
}
这个例子中,由于赋值运算符的优先级从右往左依次降低,所以先计算c%=3的结果(等价于c=c%3),再计算b*=2的结果(等价于b=b*2),最后将结果赋值给a,得到a的值为11,b的值为16,c的值为2。
3.5 其他运算符的优先级
对于其他运算符,比如位运算符、条件运算符等,其优先级是由它们本身的功能决定的。
位运算符包括按位与、按位或、按位异或等运算符。以按位与运算符为例,其优先级低于关系运算符,高于赋值运算符。下面的示例演示了位运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3, c = 8;
int result = (a < b) & (c > b);
printf("(a < b) & (c > b) = %d\n", result);
return 0;
}
这个例子中,由于位运算符的优先级低于关系运算符,所以先计算a<b和c>b的结果,最后将它们用按位与运算符连接起来,得到结果0。
条件运算符由问号和冒号组成,其优先级低于逻辑运算符,高于赋值运算符。下面的示例演示了条件运算符的优先级:
#include <stdio.h>
int main()
{
int a = 5, b = 3;
int result = (a > b) ? a : b;
printf("(a > b) ? a : b = %d\n", result);
return 0;
}
这个例子中,由于条件运算符的优先级低于逻辑运算符,所以先计算a>b的结果,然后根据结果选择a或b的值,最终得到结果5。
4. 总结
在C语言中,运算符优先级和结合性是编译器预先定义的,用于确定运算符之间的执行顺序以获取正确的表达式运算结果。
常用的运算符有算术运算符、逻辑运算符、关系运算符、赋值运算符、位运算符、条件运算符等,需要根据它们的优先级和结合性来编写正确的表达式,避免因为优先级问题导致程序出错。