结合律指的就是操作符优先级的结合方向的规律,共两种“左到右”,“右到左”,好像很简单的样子,但是,你真的全部了解了吗?你了解的是编译器真正的工作方法吗?
1、左到右的含义:就是左结合,右到左就是:右结合。
2、所谓结合:就是多个东西结合成一个整体,变为一个新的东西。
3、当一个操作符是左结合且为双目运算符时,它会把它左边的东西整个当作一个整体并与之结合,右边的只认离它最近的一个,右结合与之相反。
4、举一个算式:a+b+c,这个算式都是加号,大家优先级相同,所以转而考虑结合律,+号是左结合,所以第一个+号,先结合a,并且只认识右边和它最近的b,而对于第二个+号,会把a+b当作一个整体,并与之结合,然后只认识右边和它最近的c。结果就是 ((a)+b)+c 。
5、来一个复杂的例子:
(*((void (*)())0))()
我第一次看到它时,第一反应是,这是一个正确的表达式吗?呵呵。
1)确定主语,在这里是0,其他的都是修饰它的。
2)离0最近的是一对括号,里面的内容是:void (*)(),其实是一个类型,是我们自定义的一个函数指针类型,用小括号括起来,这个小括号是强制转换符。
3) (void (*)())0 的含义是:把0强制转换为一个函数指针类型。
4) ((void (*)())0) 表示这是一个整体,如果我们把 (void (*)())0 看作一个整体,用一个记号p替换它。
5)这样整个表达式变为: (*p)() ,这句话其实就是利用一个函数指针来调用这个函数,而指针的值p其实是0。
6)综上所述,表达式的作用:让程序指针pc(program counter)跳到地址0。
7)不过我们知道,内存中0地址是被操作系统保护的,所以,这个表达式编译没有任何问题,但执行时候会报“段错误”,因为非法引用被保护的地址。
6、回过头来,继续说优先级:上述表达式简化一下: *(类型)0 ,我们知道强转()和*号均为2级优先符,那么还是结合律在起作用了,它们的结合律是右结合,也就是说(类型)会先和右侧所有内容也就是0结合,然后结合左边的*,而*号会把右侧的所有内容(类型)0看作一个整体,然后进行取值运算,这样好像计算没有啥变化,所以这样是不必要的: *((类型)0) 。
7、再来一个简单的: **p ,作为一个2级指针,因为都是*号,所以优先级相同,结合律为右结合,那么靠近p的那个*号,首先结合p,在结合最左边的*,这时它会将*p看作一个整体进行取值运算,所以不必这样写了: *(*p) 。
8、细节的东西一定要牢牢的掌握好,这样再复杂的东西都很简单。