【Linux】gcc/g++编辑器 && 初识动静态库 && 程序翻译过程

欢迎拜访Madison-No7个人主页
文章主题:gcc/g++编辑器 && 初识动静态库 && 程序翻译过程
隶属专栏:从0到1掌握Linux
写作日期:2025年10月21号

目录

前言:

一、预处理:

预处理阶段的功能:

二、编译(生成汇编):​编辑

编译阶段的功能:

三、汇编(生成机器可识别的代码):

汇编的功能:

四、链接(生成可执行文件或库文件):

链接的功能:

[4.1 什么是库?](#4.1 什么是库?)

[4.2 目标文件和库是如何链接的?](#4.2 目标文件和库是如何链接的?)

[4.2.1 静态链接:](#4.2.1 静态链接:)

[4.2.2 动态链接:](#4.2.2 动态链接:)

[4.3 动静态库的对比:](#4.3 动静态库的对比:)

示例:

再谈动态库:


前言:

我们使用 Vim 编辑器编写的代码只是文本文件,要让代码运行起来,就需要借助 gcc 和 g++ 编译器。这两个工具分别用于编译 C 和 C++ 程序。下面我将为大家介绍它们如何完成代码的编译过程。

gcc/g++编译选项:
格式 gcc/g++ [选项] 要编译的⽂件 [选项] [⽬标⽂件]

写好的test.c源文件:

该程序需要经过翻译过程生成可执行文件,才能执行代码。

也可以跳过翻译过程,直接生成可执行文件。

📌 翻译过程是由编译和链接两个大的过程组成,而编译又可分解成:预处理、编译、汇编三个过程。

一、预处理:

将test.c文件进行预处理,生成test.i预处理文件-----gcc --E test.c --o test.i

选项"-E":开始进程程序翻译,在预处理做完的时候,就停下来。

".i"⽂件为已经过预处理的C原始程序。

**选项"-o"**是指定写到test.i文件里面,如果不加选项-o,就直接打印到下面。

vim test.i -----打开test.i文件

预处理阶段的功能:

在预处理阶段,编译器会将头文件内容(头文件中只是一些函数的声明)展开并拷贝到test.i文件中,同时执行以下操作:去除注释、替换宏定义以及处理条件编译指令。

🌟条件编译的用途?

1.同一套代码可能需要支持不同功能版本(如社区版、专业版),或根据客户需求启用 / 禁用特定模块,条件编译可通过宏定义快速切换。

2.内核源代码也是采用条件编译进行动态裁剪。

  1. 开发工具,应用软件适配不同平台。

gcc test.c -o test -DM ------其中的-DM意思是#define M->插入到代码中,也就是说可以进行命令行级别的宏定义。

🌟预处理的本质:

让编译器编辑修改我们的代码,把不需要去掉,把需要的加上,但是还是C语言,只不过和我们的源码相比变得更干净了。

二、编译(生成汇编):

将预处理文件进行编译,生成汇编代码-----gcc -S test.i -o test.s
"-S"的作用是:开始生成汇编代码,生成完了,就停下来。
".s",常为汇编代码的后缀。
vim test.s ----打开test.s文件

编译阶段的功能:

gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作, 在检查⽆误后,gcc 把代码翻译成汇编语⾔。

📌 为什么C/C++编译,要先变成汇编代码?

首先要明白计算机的硬件核心只能识别二进制,这是由半导体电路的二态性决定的;其他进制(十进制、十六进制等)是为了方便人类使用而设计的 "抽象层",最终都会被转换为二进制信号才能被硬件处理。所以我们所写的程序,最后都要转化为机器语言(二进制)才能被计算机硬件处理。

三、汇编(生成机器可识别的代码):

将汇编文件转成目标文件(二进制)-----gcc -c test.s -o test.o

"-c":只进行编译(Compile),不进行链接(Link),最终生成目标文件(Object File)而非可执行文件。

".o":目标文件(Object File),是二进制文件

vim test.o

汇编的功能:

将汇编语言的.s文件转化为机器指令,生成后缀为.o(Windows 下为.obj)的目标文件。

**注意:**生成的目标文件是二进制文件,还不能直接运行,因为它缺少程序运行所需的外部资源,比如我们写的test.c源文件中用到了printf函数,汇编过程只是把我们写的代码转化成了机器指令,对于printf函数,它的定义是在C语言标准库里面,它并没有转化为机器指令,所以我们还要经过链接:将多个目标文件和所需的库文件组合,生成可执行文件(Windows 下为.exe,Linux 下为无后缀的可执行文件)。

📌 小Tips:

如何记忆gcc编译选项:-ESc 就是键盘左上角的按键Esc,只需要记住前两个字母是大写的。

如何记忆编译过程所形成的临时文件后缀:.iso 可以理解成镜像文件

四、链接(生成可执行文件或库文件):

链接的功能:

多个目标文件(.o文件) 和所需的库文件组合到一起,生成可执行文件(Windows 下为.exe,Linux 下为无后缀的可执行文件)。

其实对于库文件无论是静态库还是动态库(共享库),本质上都是由多个目标文件(.o 文件)"打包" 组合而成的集合。关于如何"打包"形成库,以后会讲解到。

📌 我们往往喜欢的是把多个源文件编译成对应.o二进制文件,再把这些.o文件合并到一起,形成可执行文件。为什么呢?

因为对一个大型程序来说,可能有成百上千个.c源文件组成,如果直接编译成可执行文件,每次修改任意一个源文件 ,编译器都需要重新编译所有文件 ,这在文件数量多、代码量大时会极其耗时(例如一个包含 100 个文件的项目,改一行代码就要重新编译 100 个文件)。而先编译成.o目标文件时,只有被修改的源文件会重新编译,未修改的文件只需复用已生成的.o文件。最后通过链接器将所有.o文件组合成可执行文件,大幅减少重复劳动。这就像盖房子:先预制好门窗、墙体(.o文件),哪部分坏了只换哪部分,而不是每次都推倒重盖。

🌟上面提到了库文件,那什么是库文件呢?

库文件(Library File)是存储可复用代码(函数、类、数据结构等)的物理文件,是 "库" 这一抽象功能集合的具体载体。它包含编译后的二进制代码,供其他程序调用,以实现代码复用和功能扩展。

上面所写的test.c源文件,并没有定义**"printf"** 的函数实现,且在预编译中包含的"stdio.h" 中也只有该函数的声明,⽽没有定义函数的实现,那么,是在哪⾥实现**"printf"** 函数的呢? 答案是:系统把这些函数实现都被放到名为 libc.so.6 的库⽂件 中去了,在没有特别指定时,gcc 会到系统默认的搜索路径"/usr/lib "下进⾏查找,也就是链接到libc.so.6 库函数中去,这样就能实现函数**"printf"**了,而这也是链接的作⽤。

ldd + 可执行文件,可以查看可执行文件依赖了哪些库文件。

ldd +/usr/lib+指令,可以查看这些指令依赖了哪些库。通过上图可以看出ls、mkdir指令也依赖了libc.so.6库,也就是说Linux的指令也是由C语言写的。

🌟注意:

libc.so.6是 Linux 系统下的 C 语言标准库(GNU C Library,简称 glibc)的动态库文件,是绝大多数 Linux 程序运行的核心依赖。几乎所有 Linux 下的 C 程序(包括系统命令如 ls、mkdir)都依赖libc.so.6。如果这个文件损坏或丢失,系统会直接报错,甚至无法正常启动。

4.1 什么是库?

库(Library) 是一组预先编写好的代码集合,包含可复用的函数、类、数据结构或其他程序组件,目的是帮助开发者快速实现常见功能,避免重复造轮子,提高开发效率。

库分为静态库和动态库?

  • 静态库是编译好的二进制代码集合,在程序编译的 "链接阶段" 会被完整复制到目标程序中,成为可执行文件的一部分。
  • 动态库是独立存储的二进制代码文件 ,程序编译时不会被复制到可执行文件中,仅在程序运行时被加载到内存并供程序调用,多个程序可共享同一份动态库。

注意:

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

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

我们在命名自己所写的库时,比如写了一个xyz库,命名时要加上lib前缀,后缀(不同平台下不一样)。以Linux下为例,可命名为libxyz.so

4.2 目标文件和库是如何链接的?

总体上,链接分为两类:动态链接静态链接

4.2.1 静态链接:

把我们程序中使用的库方法,拷贝给我自己!静态库就像电脑商城,当有人有上网需求时,会到电脑商城去买一台专属的电脑,只供自己使用。此外静态库只有在链接时有用,一旦形成可执行程序,静态库可以不再需要了。

4.2.2 动态链接:

程序编译时,链接器仅在可执行文件中记录动态库的依赖信息 (如库文件名、函数名),不复制库代码;程序运行时 ,由操作系统加载动态库并解析函数地址。动态库就像是一个网吧,任何人想上网了,都可以去到这个网吧里。即:动态库是被所有程序所共享的,一般也被叫做共享库。这意味着,动态库只需要一个就够了,它可以满足所有程序的需求。

4.3 动静态库的对比:

1.动态库所形成的可执行程序体积一定很小。

2.可执行程序对静态库的依赖小,动态库不能缺失。

3.程序运行时,需要加载到内存,通过静态链接的程序,会在内存中出现大量重复的代码。

4.动态链接比较节省资源。

示例:

以test.c代码为例:

ldd test 查看依赖哪些库

所以gcc编辑器默认实行动态链接的。

file +可执行文件:查看具体可执行程序的信息。

同时动态链接形成的可执行文件大小:

如果非得要通过静态链接生成可执行文件:

需要在最后加上-static。

同时静态链接形成的可执行文件大小:

此外C++所以依赖的动态库是:libstdc++.so.6

再谈动态库:

动态库的代码段只需加载一份到内存,多个依赖它的可执行文件通过动态链接共享这份代码;动态库不能丢失,就像网吧被查封了,人们就不能去上网一样。一旦对应的动态库丢失,影响的不只是一个程序,可能会导致多个程序都无法正常运行。


完。

今天的分享就到这里,感谢各位大佬的关注,大家互相学习,共同进步呀!

相关推荐
小白不想白a5 小时前
【shell】每日shell练习:安全日志入侵检测/系统配置文件合规检查
运维·服务器
字节逆旅6 小时前
一个从从容容,一个连滚带爬:scp 与 rsync 的不同人生
linux
洛克大航海6 小时前
Linux 中新建用户
linux·运维·服务器
位步6 小时前
在linux系统中使用通用包安装 Mysql
android·linux·mysql
蜜蜜不吃糖7 小时前
解决Vcenter告警datastore存储容量不足问题
linux·运维·服务器
zzz.108 小时前
top命令的详解
linux·服务器·网络
东城绝神8 小时前
《Linux运维总结:基于ARM64+X86_64架构CPU使用docker-compose一键离线部署redis 7.4.5容器版分片集群》
linux·运维·redis·架构·分片集群
馨谙8 小时前
网络故障排查三板斧:路由追踪、端口检查,快速定位网络问题
linux·网络
herinspace8 小时前
如何设置电脑分辨率和显示缩放
服务器·数据库·智能手机·电脑