首页 > 编程语言 >链接--C++相关问题

链接--C++相关问题

时间:2022-12-17 10:11:19浏览次数:44  
标签:函数 -- 代码 C++ 编译 实例 链接 模板

C++的一些语言特性使之必须和编译器链接器共同支持才能工作。

  • 重复代码消除
  • 全局构造和析构

重复代码消除:

C++编译器在很多时候会产生重复的代码,比如模板(Templates)、外部内联函数和虚函数表(Virtual Function Table)都有可能在不同的编译单元里生成相同的代码。最简单的情况就拿模板来说,当模板在个编译单元里被实例化时,它并不知道自己是否在别的编译单元也被实例化了。所以当--个模板在多个编译单元同时实例化成相同的类型的时候,必然会生成重复的代码。当然,最简单的方案就是不管这些,将这些重复的代码都保留下来。不过这样做的主要问题有以下几方面。

  1. 空间浪费。可以想象-一个有几百个编译单元的工程同时实例化了许多个模板,最后链接的时候必须将这些重复的代码消除掉,否则最终程序的大小肯定会膨胀得很厉害。
  2. 地址较易出错。有可能两个指向同一个的函数的指针会不相等。
  3. 指令运行效率较低。因为现代的CPU都会对指令和数据进行缓存,如果同样一份 指令有多份副本,那么指令Cache的命中率就会降低。

怎么解决?

一个简单有效的办法就是将每个模版的实例代码都放在一个段里,每个段只包含一个模版实例。这样链接器在最终链接的时候就可以区分这些相同的模版实例段,然后将他们合并到最后的代码段。这种做法被主流的编译器采用。实例化一个带有虚函数的类,就会有自己的虚函数表,也会有重复。对于外部内联函数和虚函数表,拷贝构造,拷贝赋值函数等代码重复的问题的解决方法与之类似。

 

函数级别链接

由于现在的程序和库通常来讲都非常庞大,一个目标文件可能包含成千上百个函数或变量。当我们要用到某个目标文件中的任意一个函数或变量时,就须要把它整个地链接进来,也就是说那些没有用到的函数也被-起链接了进来。这样的后果是链接输出文件会变得很大,所有用到的没用到的变量和函数都一起塞 到了输出文件中。VISUAL C+ +编译器提供了一个编译选项叫函数级别链接( Functional-Level Linking,/Gy),这个选项的作用就是让所有的函数都像前面模板函数-样,单独保存到一个段里面。当链接器须要用到某个函数时,它就将它合并到输出文件中,对于那些没有用的函数则将它们抛弃。这种做法可以很大程度上减小输出文件的长度,减少空间浪费。但是这个优化选项会减慢编译和链接过程,因为链接器须要计算各个函数之间的依赖关系,并且所有函数都保持到独立的段中,目标函数的段的数量大大增加,重定位过程也会因为段的数目的增加而变得复杂,目标文件随着段数目的增加也会变得相对较大。

 

全局构造和析构:

C++的全局对象是在main函数之前构造的,是在main函数之后析构的。所以ELF提供了.init .fini 两个段,保存了可执行代码。.init 在main之前执行,.fini 在main之后执行。全局构造和析构就是这么实现的。

标签:函数,--,代码,C++,编译,实例,链接,模板
From: https://www.cnblogs.com/wuyun--wy/p/16988623.html

相关文章

  • 一文了解 Dubbo 的代码架构
    整体设计图例说明:图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。图中从下至上分为十层,各层均......
  • 第二十一章《万年历》第3节:项目完整代码
    万年历项目总共有3个类,这3个类的作用已在21.1.2小节中做过介绍,此处不再赘述,以下是这3个类的源代码,读者也能在本书提供的源代码文件夹中直接下载它们。CalendarFrame.javaimp......
  • 第二十章《Java Swing》第8节:选择器
    在Swing体系中有文件选择器和颜色选择器,它们分别用来帮助用户选择文件和颜色,这些选择操作是可视化桌面应用程序常用的操作,本小节将详细讲解这两种选择器的使用方式。20.8.1......
  • 第十二章《文件与I/O流》第4节:对象序列化
    对象序列化和反序列化是Java程序中经常涉及的操作,Java语言提供了专门用于序列化对象的ObjectOutputStream类和用于反序列化的ObjectInputStream类,这使得Java语言完成序列化......
  • 第十二章《文件与I/O流》第3节:字节流的使用
    字节流每次输入或输出一个字节的数据,下面的表12-4展示了java.io包下定义的字节流。表12-4字节流类流类用途InputStream字节输入流的父类OutputStream字节输出流的父类Buffer......
  • 第二十章《Java Swing》第4节:事件处理与监听器
    当程序员向窗体上添加了按钮等组件之后就能够操作这些组件,但在20.3小节的各个案例中,虽然在窗体上添加了一些按钮,但点击这些按钮并没有任何反应,因此这些按钮也就成了毫无意义......
  • 第二十章《Java Swing》第3节:布局管理器
    当把组件添加到窗体上时,并不是直接把组件添加到JFrame对象上的,而是需要先获得窗体的内容面板,然后把组件添加到内容面板上。获得内容面板的方式是调用窗体的getContentPane()......
  • 第二十章《Java Swing》第2节:窗体的创建
    JavaSwing的各种组件都是由类来定义的,这些类大部分都位于javax.swing包下,也有小部分位于java.awt包下,因此在使用这些类的时候需要在程序中引入这个包下的类。在JavaSwing......
  • 第二十章《Java Swing》第1节:Swing简介
    Java语言最早开发图形界面的应用程序被称为“AWT”,AWT是“AbstractWindowToolkit”的简称,“AbstractWindowToolkit”意为“抽象窗体工具包”。AWT组件并不是纯Java实现......
  • Java千问:Java位运算经典应用(四)
    接上篇七、判断某数是不是2的N次幂我们知道,10的0次幂是1,1次幂是10,2次幂是100...仔细观察一下这些数,你就会发现一个规律,那就是:这些数字当中,开头是1,后面N位上的数字全部是0......