• 编译器思维之结合律


    结合律指的就是操作符优先级的结合方向的规律,共两种“左到右”,“右到左”,好像很简单的样子,但是,你真的全部了解了吗?你了解的是编译器真正的工作方法吗?

    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、细节的东西一定要牢牢的掌握好,这样再复杂的东西都很简单。

  • 相关阅读:
    圣战结束
    Linux_系统管理_网络配置_命令行配置网络
    Window下MySQL安装配置
    Linux_系统管理_根据进程名kill进程
    Windows下PHP安装配置
    Apache + PHP + MySql windows xp 安装设置
    visual studio 2008生成asp.net网站的问题?
    数据库抽象层PDO和ADOdb
    正则表达式修正符
    linux搭建SVN服务器
  • 原文地址:https://www.cnblogs.com/litifeng/p/8600624.html
Copyright © 2020-2023  润新知