首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

编译器的几个概念-符号法则,强符号”和“弱符号,“强引用”和“弱引用”

编译器的几个概念-符号法则,强符号”和“弱符号,“强引用”和“弱引用”

编译器的几个概念-符号法则,强符号”和“弱符号,“强引用”和“弱引用”
符号法则
  • 当一个使用C语言编写的模块要于其他语言编写的库文件进行链接的时候,存在着符号冲突的现象——C语言模块中与库文件中存在着符号名相同的符号;随着软件规模的不断扩大,即使采用相同的编程语言,但是由于不同模块开发人员不同,也可能在不同模块中使用相同的符号名,产生符号名冲突,为此编译器乃至编程语言本身都需要对此作出修改

    C++中为此引入了函数签名的概念,每个函数签名包含这一个函数的返回类型、参数类型、函数名、所在名字空间、所在类等所有的信息,然后编译器和链接器在处理一个符号的时候,按照某种符号名称修饰法则使得每一个函数签名对应着一个修饰后的符号名。对于全局变量和静态变量同样采用类似的签名机制。——对于具体的符号修饰方法不用深究,binutils中提供了一个 c++filt 工具可以分析一个修饰后的符号名称

    符号名修饰机制使得编译器和链接器就可以分清楚各个模块中定义的每一个符号而不至产生符号名冲突了,但是由此另外一个问题则是,不同编译器采用不同的符号修饰法则,故而不同编译器编译出来的目标文件往往无法正常链接到一起。

  • 为了解决CC++编译器因为符号修饰方法不同导致的使用CC++编写的模块之间不能正确链接的问题,C++中通过 extern "C"{ } 机制来实现兼容。即包括在大括号内部的代码将被C++编译器当作纯粹的C语言代码来编译,这样C++的符号修饰方法就不会用在这段代码上。

        C++
    编译器在编译C++文件时,会自动定义 __cplusplus ,而在C标准库头文件中定义C语言用的库函数原型时,可以通过添加
    #ifdef __cplusplus
    extern "C" {
    #endif
       C
    语言库函数原型
    #ifdef __cplusplus
    }
    #endif
       
    这样的处理方式来实现CC++对于C标准库的兼容使用,否则C++编译器将会把这些C语言库函数当作是一般的C++函数,而在编译后对其符号作修正,使得链接的时候无法正确链接到C语言标准库





强符号弱符号的概念:

很多时候,用户可能并不希望使用现有库中的函数而是使用自己定义的同名库函数,这就要求允许不同程序模块中存在相同名字的函数定义——这就是强符号弱符号的概念;

对于C/C++编译器,在本目标文件中定义的函数和初始化了的全局变量为强符号,本目标文件中定义的未初始化全局变量为弱符号,而在本目标文件中使用extern引用的符号不属于强弱符号定义的范畴。链接器工作时,不允许各个模块中出现同名的强符号,而当仅有一个模块中为强符号其他模块中为弱符号时,链接器选择强符号;如果只存在多个弱符号链接器选择占用空间最大的那个——这种情况必须避免,否则错误难以发现。弱符号往往使用在库中,GCC下可以通过 __attribute__((weak))
关键字显式地定义一个弱符号。

强引用弱引用的概念:
系统中某些扩展功能模块可能时有时无,如果要求系统在两种情况下都能正常工作,这就需要在功能模块不存在时主程序中对这些扩展功能模块的引用不能报错——这就是强引用弱引用的概念。

则模块A引用模块B的一个函数时,如果模块B的这个函数不存在时,模块A不报错

默认地,本模块中所有对外部符号的引用在链接时都是强引用,该符号必须能够被正确决议(理解为绑定的同义词),否则链接器就会报错;GCC中可以通过 __attribute__ ((weakref))
关键字显式地将对一个外部符号的应用定义为弱引用,这样即使在链接的时候该符号并没有正确地找到定义,链接器也不会报错,而只是将该符号的符号值(st_value)置为0,但是这样得到的可执行程序在执行时会出错,因为当调用弱符号时,弱符号地址为0,属于非法访问。因此在程序中调用一个外部符号时,应该先判断其值是否为0,若不为0再进行调用。
返回列表