在本节中,我们来一起学习操作符的优先级,并且需要了解在相同优先级下的操作符的结合性。我们先来看一下操作符优先级和结合性的表格:
级别(由高到低) | 操作符(使用空格分隔) | 结合性 |
1 | () [] -> . | 由左向右 |
2 | ! ~ ++ -- + - * (type) sizeof | 由右向左 |
3 | * / % | 由左向右 |
4 | + - | 由左向右 |
5 | << >> | 由左向右 |
6 | < <= > >= | 由左向右 |
7 | == != | 由左向右 |
8 | & | 由左向右 |
9 | ^ | 由左向右 |
10 | | | 由左向右 |
11 | && | 由左向右 |
12 | || | 由左向右 |
13 | ?: | 由右向左 |
14 | = += -= *= /= %= &= ^= |= <<= >>= | 由右向左 |
15 | , | 由左向右 |
C语言中的操作符优先级一共分为15级,当多个操作符出现在同一个表达式中时,需要按其优先级顺序进行计算,优先级相同时按结合性进行计算。例如:我们编写一个问号表达式,并在其条件表达式中这样写:
int a = 1;
int b = 2;
printf("%c\n", a | b == 5 ? 'T' : 'F');
printf("%c\n", (a | b) == 5 ? 'T' : 'F');
T
F
我们来分析一下上面程序的运行过程:
在第一个问号表达式中,由于 ?: 的优先级低,所以要先计算?前面的条件表达式的值,而对于 a | b == 5中 | 的优先级低于 == 的优先级,所以这个表达式的值应该是先比较 b == 5 的结果为“真”,其值为1,再将a与这个结果1做或运算,结果为1。于是整个 a | b == 5 表达式的值为1,所以在接下来的问号表达中的条件判断时认为其结果为“真”,所以整个问号表达式的结果为'T'。
在第二个问号表达式中,仍然需要优先计算 ? 前面的条件表达式,而对于 (a | b) == 5这个表达式中,小括号()的优先级高于 == 比较运算符,所以要先计算 a | b 的值,结果为3,然后将3与5做比较运算即: 3 == 5,这个表达式的结果为“假”,其值为0,再将这个结果做为后续问号表达式的条件判断,所以问号表达式的结果为'F'。
我们再来看一个例子:
int x = 2;
printf("%d %lf\n", ++x, pow(3, x));
3 9.000000
上面这段代码在我的编译器下运行的结果为3和9.0,而在其它编译器下,结果可能是3和27.0。所以为了保证代码的一致性和可读性,我们应该将上面的代码书写这样:
int x = 2;
++x;
printf("%d %lf\n", x, pow(3, x));
3 27.000000
我们再来看看使用自增运算符对数组做赋值操作的程序:
int a[3] = { 7, 8, 9 };
int i = 0;
a[i] = ++i;
对于上面代码中对数组变量a[i]做赋值操作的赋值之后数组元素的值分别为7、1、9。同样在不同的编译下,运行结果可能不同。所以在编写代码时要了解你的编译器运行机制,并清楚的知道编译器将如何处理这样的程序代码。当然好的程序应该尽量避免这样对不同编译器有不同运行结果的代码,例如这样来书写:
int a[3] = { 7, 8, 9 };
int i = 0;
++i;
a[i] = i;