【linux】5:编译器-gcc/g++的使用

目录

一、背景知识

二、gcc编译选项

[2.1 预处理](#2.1 预处理)

[2.2 编译](#2.2 编译)

[2.3 汇编](#2.3 汇编)

[2.4 链接](#2.4 链接)

三、动态链接和静态链接

四、静态库和动态库

五、代码实现动态链接

方式一:一起编译

方式二:分开编译


gcc和g++所对应的选项都是完全一样的,只不过gcc只能用来编译c语言,g++既能编译c又能编译c++。

一、背景知识

1.预处理(进行宏替换/去注释/条件编译/头文件展开等)

2.编译(生成汇编)

3.汇编(生成机器可识别代码)

4.链接(生成可执行文件或库文件)

二、gcc编译选项

在我们写完c语言代码之后,我们可以使用gcc来进行编译,默认就给我们生成一个a.out的可执行程序,运行这个a.out的可执行程序,就可以执行我们写的代码了,如下所示:

默认生成的可执行程序是a.out,如果我们想要生成其他名字的可执行程序可以使用-o选项:

gcc code.c -o mycode

或者 gcc -o mycode code.c

这两种写法都可以,但是要记住-o后面接的是生成的可执行程序mycode

2.1 预处理

gcc -E code.c -o code.i

-E选项:开始进行对code.c程序翻译,在预处理做完的时候,就停下来,生成一个code.i的中间文件。code.i还是c语言代码。

2.2 编译

gcc -S code.i -o code.s

或者gcc -S code.c -o code.s

-S选项:开始进行程序翻译,在编译做完的时候,就停下来,生成一个code.s的中间文件。此时code.s是汇编语言代码

2.3 汇编

gcc -c code.s -o code.o

或者gcc -c code.c -o code.o

-c选项:开始进行程序翻译,在汇编做完的时候,就停下来,生成一个code.o

code.o文件叫做可重定位目标文件,在windows的vs中,代码生成的就是xxx.obj文件。已经是二进制文件了。但是还是无法执行的。为什么呢?

因为code.o仅仅只是将我们自己写的代码变成二进制文件了,代码里面还用到了printf,cout等等,包含了很多库方法,在我们的程序里面,还没有和库方法关联起来,所有我们的code.o程序是不可能运行的。举个例子,代码里面不是用到了printf方法嘛?但是code.o里面根本没有printf的实现。所以需要经过链接才能形成可执行程序。

2.4 链接

gcc code.o -o code

gcc本身是编译c语言的,会在系统里面帮我们去找code.o依赖了哪一个库。

三、动态链接和静态链接

在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个*.c文件会形成一个*.o文件,为了满足前面说的依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个链接的过程就是静态链接。静态链接的缺点很明显:

  • 浪费空间:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,如多个程序中都调用了printf()函数,则这多个程序中都含有printf.o,所以同一个目标文件都在内存存在多个副本;
  • 更新比较困难:因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。但是静态链接的优点就是,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。

动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。
动态链接其实远比静态链接要常用得多。比如我们查看下code这个可执行程序依赖的动态库,会发现它就用到了一个c动态链接库:

ldd命令用于打印程序或者库文件所依赖的共享库列表。

在这里涉及到一个重要的概念:库

  • 我们的c程序中,并没有定义"printf"的函数实现,且在预编译中包含的"stdio.h"中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实"printf"函数的呢?
  • 最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径"/usr/lib"下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数"printf"了,而这也就是链接的作用

四、静态库和动态库

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为"a"
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为"so",如前面所述的libc.so.6就是动态库。gcc在编译时默认使用动态库。完成了链接之后,gcc就可以生成可执行文件,如下所示。gcc hello.o -o hello
  • gcc默认生成的二进制程序,是动态链接的,这点可以通过file命令验证。

Linux下,动态库XXX.so,静态库XXX.a

Windows下,动态库XXX.dll,静态库XXX.lib

五、代码实现动态链接

我们创建5个文件,分别是main.c,code1.h,code2.h,code1.c,code2.c,然后将code1.h,code2.h,code1.c,code2.c放入lib的文件夹里面,

main.c内容如下:

#include<stdio.h>

#include"code1.h"

#include"code2.h"

int main()

{

fun1();

fun2();

}

code1.h内容如下:

#pragma once

void fun1();

code1.c内容如下:

#include<stdio.h>

void fun1()

{

printf("hello fun1()\n");

}

code2.h内容如下:

#pragma once

void fun2();

code2.c内容如下:

#include<stdio.h>

void fun2()

{

printf("hello fun2()\n");

}

方式一:一起编译

将上面5个文件放在一个文件夹下面,将main.c,code1.c,code2.c一起编译,如下所示:

方式二:分开编译

我不想让其他人可以看见code1.c和code2.c的代码实现,我们就可以对目标文件分开编译,首先将.c文件编译成.o文件,然后将所有的.o文件链接起来,如下所示:

这里只有3个.o文件,如果是100个.o文件呢?我们可以将所有的.o文件打包合并起来,这样就形成了一个C语言库。
在linux系统中:

/usr/include文件夹里面包含头文件。

/usr/lib64文件夹里面包含库文件,库文件就是.o文件的集合

相关推荐
你真是饿了3 小时前
7.进程间通信
linux·运维·服务器
TEC_INO3 小时前
Linux_12:通过多线程获取VENC的H264码流数据
linux·运维·服务器
无证驾驶梁嗖嗖4 小时前
git_lab_事故恢复全过程(ubuntu_22
linux·git·ubuntu
小程同学>o<4 小时前
Linux 应用层开发入门(二十)| 获取输入系统设备数据
linux·嵌入式软件·嵌入式应用层·应用层开发·linux应用层开发
yuanmenghao5 小时前
Linux 性能实战 | 第 17 篇:strace 系统调用分析与性能调优 [特殊字符]
linux·python·性能优化
hweiyu005 小时前
Linux 命令:setfacl
linux·运维·服务器
wdfk_prog5 小时前
[Linux]学习笔记系列 -- [drivers]char
linux·笔记·学习
社会零时工5 小时前
Ubuntu安装的OpenCV如何更换版本
linux·opencv·ubuntu
m0_528749005 小时前
C语言错误处理宏两个比较重要的
java·linux·算法