【浅谈】编译与链接

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/85045267

1. 编译与链接

编译与链接的过程可分解为四个步骤,分别是预处理编译汇编以及链接,可以用一张图来描述此过程:
在这里插入图片描述

2. 预处理

我们接下来都以示例来描述相应的过程

以这样的一个示例:

#include <iostream>
using namespace std;
int main()
{
        cout << "hello world\n" << endl;
        return 0;
}

手动执行预处理(-E表示预处理):

g++ -E hello.cpp -o hello.i

在这里插入图片描述
得到hello.i文件,可以用vim hello.i查看这一文件:
在这里插入图片描述

总结一下预处理过程中主要做了什么工作:

  • 1.将所有的#define删除,并且展开所有的宏定义(例:#define a b,即将程序中所有a用b替换)
  • 2.处理所有的条件预编译指令,比如#if, #ifdef,#elif,#else,#endif
  • 3.处理#include预编译指令,将被包含的文件插入到该预编译指令的位置
  • 4.过滤所有的注释"//"和’/**/'中的内容
  • 5.添加行号和文件名标识,比如# 1 “hello.cpp”
  • 6.保留所有的#pragma编译器指令

3. 编译与汇编

还是以上述那个示例,执行以下代码,对预处理得到的.i文件进行编译得到汇编代码(.s文件):

g++ -S hello.i -o hello.s

在这里插入图片描述

用vim hello.s查看汇编代码:
在这里插入图片描述

------------------------------------------总结-----------------------------------------------

编译过程就是把预处理完的文件进行一系列的词法分析语法分析语义分析以及优化后产生相应的汇编代码

以一张图来描述该过程:

4. 链接

  • 把每个源代码模块独立地编译,然后按照要求将它们”组装”起来,这个组装模块的过程就是链接
  • 从原理上讲,它的工作就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定位等步骤
  • 链接大致可分为静态链接动态链接两种方式

4.1 静态链接

  • 所谓静态链接指的就是对函数库的链接放在编译时期完成
  • 与目标文件有关联的函数库被链接合成一个可执行文件,程序在运行时与函数库无瓜葛;这些函数库被称为静态库,通常文件名为"libxxxx.a"的形式
  • 下面以一个示例来演示该如何编译和使用静态链接库:
//add.h
#ifndef ADD_H
#define ADD_H
int add(int a, int b);
#endif
//add.cpp
#include "add.h"
int add(int a, int b)
{
        return a+b;
}
//sub.h
#ifndef SUB_H
#define SUB_H
int sub(int a, int b);
#endif
//sub.cpp
#include "sub.h"
int sub(int a, int b)
{
        return a-b;
}
//main.cpp
#include "add.h"
#include "sub.h"
#include <iostream>
using namespace std;
int main()
{
        cout << "1+2=" << add(1,2) << endl;
        cout << "1-2=" << sub(1,2) << endl;
        return 0;
}

在这里插入图片描述

  1. 首先将add.cpp与sub.cpp编译成.o文件:
g++ -c add.cpp
g++ -c sub.cpp

在这里插入图片描述
2. 由.o文件创建静态库(.a文件):

ar cr libmymath.a sub.o add.o
ar tv libmymath.a  //查看库文件中的.o文件

在这里插入图片描述
了解更多有关ar命令linux ar命令

  1. 在程序中使用静态库:
g++ -o main main.cpp -L. -lmymath   //生成.main文件

在这里插入图片描述

g++命令生成目标文件时指定静态库名(即指定mymath而不是libmymath.a),g++将会从静态库中将公用函数连接到目标文件中;g++会在静态库名前加上前缀lib,然后追加扩展名.a得到静态库文件名来查找静态库文件

  1. 执行main文件:
    在这里插入图片描述

4.2 动态链接

  • 把对一些库函数的链接载入推迟到程序运行时期,这就是动态链接
  • 通常文件名为"libxxxx.so"
  • 还是以上面的程序来演示编译和使用动态链接库:
  1. 生成动态库文件:
//可以用以下命令
g++ -fPIC -o add.o -c add.cpp
g++ -fPIC -o sub.o -c sub.cpp
g++ -shared -o libmymath.so add.o sub.o
//也可以用以下一条命令
g++ -shared -o libmymath.so add.cpp sub.cpp

//-fPIC表示编译为位置独立的代码

在这里插入图片描述

  1. 使用g++命令生成目标文件:
g++ -o main main.cpp -L. -lmymath

在这里插入图片描述
我们发现这样子直接编译报错了,说找不到动态库文件libmymath.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件,若找到,则载入动态库,否则将提示上述的错误
既然找到了问题所在,那我们直接将该动态库拷贝到/usr/lib目录中

cp libmymath.so /usr/lib/

在这里插入图片描述

4.3 静态链接库、动态链接库各自的特点

  • 1.动态链接库有利于资源共享

当某个程序在运行中要调用某个动态链接库函数的时侯,操作系统首先会查看所有正在运行的程序,看在内存中是否有此库函数的拷贝,如果有,则让其共享那一个拷贝,没有才链接载入;而静态链接库,如果系统中对各程序都要调用某个静态链接库函数,则每个程序都要将这个库函数拷贝到自己的代码段,显然更占用内存资源

  • 2.将一些程序升级变得简单

用静态链接库,如果库发生变化,使用库的程序要重新编译;使用动态库,只要动态库提供给该程序的接口没变,只要重新用新生成的动态库替换原来就可以了

  • 3.可以做到链接载入完全由程序员在程序代码中控制

程序员在编写程序时,可以明确指出什么时候或者什么情况下,链接载入哪个动态库函数

  • 4.由于静态库在编译时,就将库函数装载到程序中,而动态库函数必须在运行时才被装载,所以程序在执行时,用静态库速度更快一些

-----------------------------------------------get-----------------------------------------------

1.编译与链接的几大步骤
2.静态链接与动态链接的使用
3.静态链接与动态链接的比较以及使用

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/85045267