编程规范还是尽量使用小括号来区分优先级问题,有利于自己检验和别人查看,运算符有“目”和“结合性”的概念,“目”就是“眼睛”的意思,一个运算符需要几个数就叫“几目”。比如+,要使用这个运算符需要两个数,如 1+2。对+而言,1和2就像它的两只眼睛,所以这个运算符是双目的。整个C语言中只有一个三目运算符,即条件运算符?: 。“结合性”是针对优先级相同时,先计算什么由结合性决定。C语言中大多数运算符的结合性都是从左往右,只有三个运算符是从右往左的。单目运算符,是三目运算符,还有一个就是双目运算符中的赋值运算符=。==双目运算符中只有赋值运算符的结合性是从右往左的,其他的都是从左往右。==对于优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符。逻辑运算符中“逻辑非 !”除外。
这里举个比较难的例子加深理解:
int a=b=c=d=1;
a=++b>1||++c>1&&++d>1;
cout<<a<<b<<c<<d;
答案是1211,这里需要提到其他几个在C/C++中的运算规则。
- &&在运算时,左边为0则不再计算,直接返回0;
- ||在运算时,左边为1则不再计算,直接返回1;这两个和逻辑与和逻辑非的特性有关,&&两边同时为1才为1,||只要有一个是1就为1;
- 计算机在计算表达式的时候,会先将正常表达式转化为后缀表达式,1 + 2 * 3会被写做是1 2 3 * +,再利用栈的特性去解决问题,就好像是看做是1+ ( 2 * 3 )。
所以上面的表达式就可以看作是()||(),只需要算++b>1返回值为1,整体的返回值就为1了,则只有b自增,其他的都没有运算。所以表达式的计算问题不仅仅只限于表达式的优先级,而是有关于整个计算机基础的,所以多多使用加以理解才是王道。
下面做一个表格把常理解错的提醒一下。
优先级问题 | 表达式 | 错误理解 | 实际运行 |
---|---|---|---|
. 的优先级高于 *(-> 操作符用于消除这个问题) | *p.f | p 所指对象的字段 f,等价于:(*p).f | 对 p 取 f 偏移,作为指针,然后进行解除引用操作,等价于:*(p.f) |
[] 高于 * | int *ap[] | ap 是个指向 int 数组的指针,等价于:int (*ap)[] | ap 是个元素为 iny指针的数组,等价于:int *(ap []) |
函数 () 高于 * | int *fp() | fp 是个函数指针,所指函数返回 int,等价于:int (*fp)() | fp 是个函数,返回 int*,等价于:int* ( fp() ) |
== 和 != 高于位操作 | (val & mask != 0) | (val &mask) != 0 | val & (mask != 0) |
== 和 != 高于赋值符 | c = getchar() != EOF | (c = getchar()) != EOF | c = (getchar() != EOF) |
算术运算符高于位移运算符 | msb << 4 + lsb | (msb << 4) + lsb | msb << (4 + lsb) |
逗号运算符在所有运算符中优先级最低 | i = 1, 2 | i = (1,2) | (i = 1), 2 |