4. 运算符总结

到此之止,除了和指针相关的运算符还没讲之外,其它运算符都讲过了,是时候做一个总结了。

运算符+ - * / % > < >= <= == != & | ^ 以及各种复合赋值运算符要求两边的操作数类型一致,条件运算符?:要求后两个操作数类型一致,这些运算符在计算之前都需要做Usual Arithmetic Conversion。

下面按优先级从高到低的顺序总结一下各种运算符,每一条所列的各运算符具有相同的优先级,对于同一优先级的多个运算符按什么顺序计算也有说明,双目运算符就简单地用“左结合”或“右结合”来说明了。和指针有关的运算符* & ->也在这里列出来了,以后再详细解释。

1、标识符、常量、字符串和用()括号套起来的表达式是组成表达式的最基本单元,在运算中做操作数,优先级最高。

2、后缀运算符,包括数组取下标[]、函数调用()、结构体取成员.、指向结构体的指针取成员->、后缀自增++、后缀自减--。如果一个操作数后面有多个后缀,按照离操作数从近到远的顺序(也就是从左到右)依次运算,比如a.name++,先算a.name,再++,这里的.name应该看成a的一个后缀,而不是把.看成双目运算符。

3、单目运算符,包括前缀自增++、前缀自减--、sizeof、类型转换()、取地址运算&、指针间接寻址*、正号+、负号-、按位取反~、逻辑非! 。如果一个操作数前面有多个前缀,按照离操作数从近到远的顺序(也就是从右到左)依次运算,比如!~a,先算~a,再求!。

4、乘*、除/、模%运算符。这三个运算符是右结合的。

5、加+、减-运算符。右结合。

6、移位运算符<<和>>。右结合。

7、关系运算符< > <= >=。右结合。

8、相等性运算符==和!=。右结合。

9、按位与&。右结合。

10、按位异或^。右结合。

11、按位或|。右结合。

12、逻辑与&&。右结合。

13、逻辑或||。右结合。

14、条件运算符:?。在第 2 节 “if/else语句”讲过Dangling-else问题,条件运算符也有类似的问题。例如a ? b : c ? d : e是看成(a ? b : c) ? d : e还是a ? b : (c ? d : e)?C语言规定是后者。

15、赋值=和各种复合赋值(*= /= %= += -= <<= >>= &= ^= |=)。左结合。

16、逗号运算符。右结合。

[K&R]第2章也有这样一个列表,但是对于结合性解释得非常不清楚。左结合和右结合这两个概念应该只对双目运算符有意义。对于前缀、后缀和三目运算符我单独做了说明。C语言表达式的详细语法规则可以参考[C99]的Annex A.2,其实语法规则并不是用优先级和结合性这两个概念来表述的,有一些细节用优先级和结合性是表达不了的,所以只有看C99才能了解完整的语法规则。

习题

1、以下代码查找和打印0~1024之间所有256的倍数,对吗?

int i = 0;
for (; i <= 1024; ++i)
{
	if (i & 0xff == 0)
	{
		printf("%d\n",i);
	}
}