Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深度解析Linux中的编译器gcc/g++

深度解析Linux中的编译器gcc/g++

作者头像
凯子坚持C
发布于 2025-01-17 00:55:51
发布于 2025-01-17 00:55:51
16200
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

gcc只用来编译C语言

g++用来编译C/C++

程序的翻译步骤经历四个过程的

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

这个-E的意思是从现在开始,进行程序的翻译,一但预处理做完了,就停下来

那么这里的code.i保存的是预处理之后的结果

我们这里的-o选项就是指明了我们的生成文件的名称了

那么我们将这个code.i文件和原始的code.c进行对比下

对比发现我们的源文件有24行,预处理结算的代码有800多行

我们在这个阶段进行了进行宏替换/去注释/条件编译/头文件展开等等操作

所谓的头文件展开就是将你要包含的头文件的相关内容拷贝到我们的源文件里面

2、编译(生成汇编)

输入命令gcc -S code.i -o code.s

生成了一个code.s的文件

那么这个文件里面的都是汇编语言了

这个-S的意思即是从现在开始进行程序翻译,编译做完,形成汇编,就停下来

3、汇编(生成机器可以识别的代码)

输入命令gcc -c code.s -o code.o

-c的意思是开始进行程序的翻译,汇编完成就停下来

我们生成的code.o文件是不能执行的,并且可以重定位目标二进制文件的

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

我们的.o,库文件进行链接,然后就能进行执行的操作

我们可以通过ESc来记住这个前面三个过程的选项

那么分别形成的文件的后缀就是.iso了

如果我们出现这种情况的话,那么就是说明系统觉得我们没有权限

所以我们是需要进行配置文件的更改操作的

我们需要进入到/etc/sudoers这个文件里面,我们需要使用我们的root账户,不然得话我们进去之后什么都看不见的

我们使用su切换到管理员然后进入到我们的vim模式

对文件进行修改,我们输入99gg直接跳转到第99行就行了

然后我们将root那一行进行复制

然后再粘贴到下面,将我们其他的用户名输入进去我们再输入:wq!就行了

强制保存退出

然后我们的配置文件就修改成功了

那么我们的文件就能进行文件的创建和查看的操作了

为什么我们需要进行汇编呢?

减少语言开发的成本

下面的就是编译器自举的操作

动静态库和动静态库链接

库:动态库、静态库

Linux中的动态库的文件—libXXX.so

在Linux中的静态文件----libXXX.a

Windows中的动态库—XXXX.dill

在Windows中的动态库—XXXX.lib

如果我们使用的是gvv -c code.c的话,我们没有在后面指定上我们的文件名称的话,那么就会生成同名的.o文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[kk@hcss-ecs-28de lesson5]$ gcc -c code.c
[kk@hcss-ecs-28de lesson5]$ ll -al
total 16
drwxrwxr-x 2 kk kk 4096 Dec 27 14:49 .
drwx------ 5 kk kk 4096 Dec 27 14:47 ..
-rw-rw-r-- 1 kk kk   69 Dec 27 14:47 code.c
-rw-rw-r-- 1 kk kk 1504 Dec 27 14:49 code.o
[kk@hcss-ecs-28de lesson5]$ 

前面的知识:我们的这个code.o是不能进行执行的操作的,我们是需要进行链接的

我们可以再次进行gcc code.o -o mycode的可执行文件

这个操作我们叫做链接了

一点开始链接了,那么就形成了一个mycode的文件

我们使用ldd mycode来进行查看我们是否存在这个链接成功了

那么我们根据这个链接找到的就是这个libc- 2.17.so

这个就是我们的C标准库

gcc会帮你进行c语言的库的链接操作部

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[kk@hcss-ecs-28de lesson5]$ file mycode 
mycode: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=8bbc1c98d1da83282c41f5b2eca3a7a97847630a, not stripped
[kk@hcss-ecs-28de lesson5]$ 

这里我们可以发现我们这里的是动态链接

那么我们如何行成静态链接呢?

我们输入命令gcc code.o -o mycode -static

那么这个就是采用静态链接的方案

所以gcc默认形成的可执行程序是动态链接的

gcc -static:我们要求程序进行静态链接

我们这里如果要使用动态链接的话就要使用动态库

如果要使用静态链接的话就使用静态库

需要存在对应的库,我们的Linux默认只存在动态库

sudo yum install glibc-static libstdc++-static -y我们可以使用这个命令进行静态库的安装操作

形成的可执行程序里面的static的体积比较大,

动态链接就是将库的地址拷贝到我们的可执行程序里面,动态库也称之为共享库

动态库不能缺失,不然得话会导致所有的程序运行出错的

静态链接:将我们要的库方法实现,直接拷贝到我们的可执行程序中

所以这就是被为什么我们采用静态链接时候我们的可执行程序的大小比动态链接的时候大了

因为静态链接不再依赖任何库

我们这里的图比较形象

将我们视为可执行程序

学校视作内存

网吧视作动态库

编译器就是大哥

可执行程序和编译器产生链接,告诉我们动态库的地址信息

然后我们在内存中执行程序的时候然后执行到上网这一步了

我们直接就调用动态库了

上完了网吧回学校就是库函数调用完毕了

假如说你的同学都是可执行程序,他们都会进行调用动态库的操作,但是这个时候网吧倒闭了

就是动态库缺失了,那么我们可执行程序的就会出问题了

那么现在我们随身带上电脑,就是我们可执行程序直接将我们的库方法实现,就不用进行库函数的调用了

那么这个就是静态操作

直接将可执行程序和库方法合并起来,内存要大得多

我们可执行程序的时候默认是动态链接的,因为可执行文件的体积比较小

动态链接的优点:生成的可执行文件比较小

动态链接的缺点:一但这个库丢失了,那么我们所有的可执行文件都运行不了了

静态链接的优点:一但编译好不依赖任何库,浪费磁盘和内存空间

在 Linux 系统中,gccg++ 是 GNU 编译器集合中的核心工具,分别用于编译 C 和 C++ 程序。它们支持生成可执行文件,并且能够链接静态库和动态库。以下是关于它们以及动、静态库的详细解析。


一、GCC/G++ 的基本使用

1. 编译阶段

源文件编译为目标文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -c file.c -o file.o
g++ -c file.cpp -o file.o
  • -c 选项表示只进行编译,不链接。
  • 生成的 .o 文件是目标文件。
2. 链接阶段

目标文件链接为可执行文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc file.o -o output
g++ file.o -o output
3. 编译并链接(一步完成)

直接编译源文件并生成可执行文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc file.c -o output
g++ file.cpp -o output

二、Linux 动态库与静态库

1. 静态库

特点:

  • 静态库在编译时被直接嵌入到可执行文件中,生成的二进制文件是独立的。
  • 文件后缀通常为 .a

创建静态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -c file1.c file2.c  # 编译生成目标文件
ar rcs libmylib.a file1.o file2.o  # 创建静态库
  • ar 是静态库管理工具。
  • rcs 参数:
    • r:插入文件到库中。
    • c:创建库。
    • s:生成符号索引表。

使用静态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc main.c -L. -lmylib -o output
  • -L.:指定库所在路径。
  • -lmylib:链接静态库 libmylib.a(注意去掉前缀 lib 和后缀 .a)。
2. 动态库

特点:

  • 动态库在运行时被加载,可执行文件依赖于动态库文件。
  • 文件后缀通常为 .so
  • 动态库具有节省存储空间和支持共享的优点。

创建动态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -fPIC -c file1.c file2.c  # 编译为位置无关代码
gcc -shared -o libmylib.so file1.o file2.o  # 创建动态库
  • -fPIC:生成位置无关代码(Position Independent Code)。
  • -shared:指定生成共享库。

使用动态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc main.c -L. -lmylib -o output
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH  # 指定动态库路径
./output
  • LD_LIBRARY_PATH 环境变量指定动态库的查找路径。

三、动静态库的选择

对比项

静态库

动态库

文件大小

可执行文件较大,库内容嵌入其中

可执行文件较小,运行时需要库文件支持

运行效率

加载速度更快,无需查找库文件

运行时加载,可能略慢

共享能力

不支持共享,每个程序都包含独立的副本

支持共享,多个程序可以使用同一个库

版本控制

更新库需要重新编译程序

更新库无需重新编译,但需注意兼容性


四、GCC/G++ 动静态库的链接细节

1. 链接顺序

编译器按照以下顺序查找库:

  1. 指定的路径(-L 参数)。
  2. 环境变量 LD_LIBRARY_PATH 中指定的路径。
  3. 系统默认路径 /lib/usr/lib
2. 动态库优先级

如果同一个路径下同时存在静态库和动态库,默认优先链接动态库。

强制使用静态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc main.c -L. -static -lmylib -o output
  • -static 选项强制链接静态库。
3. 解决动态库版本兼容问题

动态库通常通过符号链接来管理版本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
libmylib.so -> libmylib.so.1.0
libmylib.so.1 -> libmylib.so.1.0
  • 可执行文件加载 libmylib.so,符号链接指向具体版本。

五、工具补充

查看目标文件/库文件的符号表:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nm file.o
nm libmylib.a
nm libmylib.so

查看动态库依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ldd output
  • 输出依赖的动态库列表及路径。

检查动态库是否导出特定符号:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
objdump -T libmylib.so | grep symbol_name

添加动态库路径到系统默认: 将动态库路径添加到 /etc/ld.so.conf,然后运行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo ldconfig
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Linux】gcc/g++配置
7. 动态库是共享的,一旦丢失,所有依赖动态库的程序都会出错。
风中的云彩
2025/05/01
530
【Linux】gcc/g++配置
Linux编译器---gcc/g++使用详解
更加详细的介绍,可以参照这篇博客:C语言翻译环境:预编译+编译+汇编+链接详解-CSDN博客
P_M_P
2024/02/24
9120
Linux编译器---gcc/g++使用详解
Linux编译器-gcc/g++使用
gcc mycode.c -0 mytest,后,./mytest就可以编译了,相当于把a.out重命名了
ljw695
2024/10/18
1340
Linux编译器-gcc/g++使用
Linux下Centos7中的gcc/g++
可能对于没有配置过的centos来说,会无法编译成功。为什么呢?那是由于gcc的版本在默认的情况之下是取了一个适中的版本,不算太新,正好又不能编译for循环,所以导致这样不能进行编译。 如果想要编译的话,可以根据提示信息,进行改写一下gcc命令
薛定谔方程难
2024/07/27
1060
Linux下Centos7中的gcc/g++
【Linux修炼】6.gcc/g++及Makefile【工具篇】
在C语言中,我们已经学过程序的编译和链接,在这里将复习一下我们之前所学的内容并引出后续gcc/g++的内容。
每天都要进步呀
2023/03/28
5730
【Linux修炼】6.gcc/g++及Makefile【工具篇】
【Linux篇】基础开发工具-编译器gcc/g++
 在Liunx中存在着两种编译器gcc/g++,gcc是只用来编译c语言的编译器,而g++可以编译c/c++。 程序的翻译过程需要经历四个步骤:预处理,编译,汇编,链接。
_孙同学
2024/12/25
1810
【Linux篇】基础开发工具-编译器gcc/g++
Linux探秘坊-------3.开发工具详解(2)
之前我们在makefile里都是直接写文件名的,这里使用 类似宏替换 的方式替换命令和文件,记住,在使用替换时要加上$()
hope kc
2025/01/21
790
Linux探秘坊-------3.开发工具详解(2)
Linux编译器-gcc/g++使用
选项 “-E”, 该选项的作用是让 gcc 在预处理结束后停止编译过程。
绝活蛋炒饭
2024/12/16
3110
Linux编译器-gcc/g++使用
深入了解Linux —— 理解gcc编译器
编译阶段,gcc要检查代码规范性、是否存在语法错误,并且确定代码实际的操作;检查无误后将代码翻译成汇编语言。
星辰与你
2024/12/29
2730
深入了解Linux —— 理解gcc编译器
【linux学习指南】Linux编译器 gcc和g++使用
预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
学习起来吧
2024/09/11
3120
【linux学习指南】Linux编译器 gcc和g++使用
全面掌握APT、Vim和GCC:Ubuntu软件管理与开发指南
在 **Ubuntu** 系统中,软件包管理器用于安装、更新、删除和管理软件包。Ubuntu 主要使用 APT(Advanced Package Tool) 作为软件包管理系统,并提供了多种工具和命令来简化软件管理
HZzzzzLu
2024/12/26
1420
全面掌握APT、Vim和GCC:Ubuntu软件管理与开发指南
Linux基础——Linux开发工具(中)_gcc/g++
前言:在上一篇我们简单介绍了yum,vim的一些常用的指令和模式,现在让我们来进一步了解其他的Linux环境基础开发工具gcc/g++,gdb。
Eternity._
2024/06/14
1910
Linux基础——Linux开发工具(中)_gcc/g++
Linux基本工具——gcc/g++与make/Makefile
接下来我们用gcc编译器来运行一下,当然不是要完全编译,而是先让他预处理一下:
有礼貌的灰绅士
2023/03/28
6640
Linux基本工具——gcc/g++与make/Makefile
【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用
格式: gcc [选项] 要编译的文件 [选项] [目标文件],gcc / g++安装: sudo yum install -y gcc-c++。安装后的编译器默认的版本是较低的,我们可以使用选项-std=c99(即使用c99标准),-std=c++11(即使用c++11的标准)来进行版本提升。使用-o选项,可以将编译生成的可执行重命名。最后使用./可执行,来运行程序。如下:
用户11029269
2024/03/19
4710
【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用
编译器gcc/g++ --【Linux基础开发工具】
• 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后, gcc 把代码翻译成汇编语言。
小志biubiu
2025/02/27
3370
【Linux】Linux开发工具-vim / 编译器-gcc/g++ / 调试器-gdb / git操作 / 项目自动化构建工具-make/Makefile
我们在Windows中有很多的编译环境,大家应该都很熟悉,但是在Linux中,我们怎么写代码呢?
用户10925563
2024/06/04
1240
【Linux】Linux开发工具-vim / 编译器-gcc/g++ / 调试器-gdb / git操作 / 项目自动化构建工具-make/Makefile
Linux中编译器-gcc/g++的使用
上面的过程对应的选项正好对应键盘左上角 Esc 按键, 方便我们进行记忆, 不过E S 大写, c小写
用户11317877
2024/11/15
2050
Linux中编译器-gcc/g++的使用
【Linux】手把手教你从零上手gcc/g++编译器
然后我们使用gcc的只激活预处理选项,将生成的文件定向输入到新文件test.i中:
修修修也
2024/08/17
1870
【Linux】手把手教你从零上手gcc/g++编译器
【Linux系统编程】Linux下的编译器——gcc/g++的使用 及 动态库和静态库的认识
gcc (GNU Compiler Collection) 和 g++ 是 Linux 系统上最常用的编译器。它们是 GNU 组织开发的一套开源编译器工具集。
YIN_尹
2024/01/23
2.3K0
【Linux系统编程】Linux下的编译器——gcc/g++的使用 及 动态库和静态库的认识
C/C++生态工具链——gcc/g++编译器使用指南
GCC的全称是GNU Compiler Collection,是GNU工具链中的一种。GCC不仅支持C/C++语言,还支持Fortran/Ada/Java等语言的编译。
Coder-ZZ
2023/02/23
2.8K0
C/C++生态工具链——gcc/g++编译器使用指南
推荐阅读
相关推荐
【Linux】gcc/g++配置
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档