【Linux】编译器 - gcc 函数库

news2025/1/16 2:41:21

目录

一、背景知识

二、gcc如何执行

1、预处理

2、编译

3、汇编

4、链接

三、函数库

1、初识函数库

2、动静态库

2.1、动态库

2.2、静态库

2.3、动静态库的选择


一、背景知识

使用 vim 编辑器完成代码书写之后,我们需要使用 Linux 中的编译器 gcc 来对程序进行翻译,其本质是把程序从文本类文件翻译成二进制可执行文件,翻译过程包括:预处理(进行宏替换)、编译(生成汇编)、汇编(生成机器可识别代码)、连接(生成可执行文件或库文件)。

二、gcc如何执行

1、预处理

主要完成头文件展开、条件编译、宏替换、去注释等等工作。

预处理结构后,C语言还是C语言,没有发生变化。

预处理指令:

gcc -E [目标文件名] -o [生成文件名]

 -E :从现在开始进行程序的翻译,预处理做完,就停下来。

 -o :指定生成文件的文件名。-o 选项的位置可以不固定,但是 -o 选项后面紧跟着的,一定是生成的文件的名称。

我们先创建一个文件 myfile.c ,使用 vim 编译器写入代码:

保存退出后,对其进行预处理操作:

[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ vim myfile.c
[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ gcc -E myfile.c -o myfile.i
[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ ll
total 24
-rw-rw-r-- 1 ljb ljb   525 Jan 12 17:56 myfile.c
-rw-rw-r-- 1 ljb ljb 17086 Jan 12 17:57 myfile.i

可以看到已经生成了一个可执行文件 myfile.i 。我们把它打开,并与 myfile.c 对比:

可以看到原本 33 行的代码,预处理之后变成了 800 多行。这是因为 预处理 工作把程序里的头文件都拷贝到了源文件之中,这个工作叫做头文件展开。

这里打印了 "hello PRINT" ,而没有打印 "hello None",是因为在程序开始时定义了宏 PRINT ,所以 "hello None" 被条件编译裁剪掉了。

2、编译

完成将c语言编译,形成汇编语言。

编译指令:

gcc -S [目标文件名] -o [生成文件名]

 -S :从现在开始进行程序的翻译,编译做完,就停下来。

我们对刚刚预处理形成的 myfile.i 文件进行编译:

[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ gcc -S myfile.i -o myfile.s
[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ ll
total 28
-rw-rw-r-- 1 ljb ljb   525 Jan 12 20:16 myfile.c
-rw-rw-r-- 1 ljb ljb 17086 Jan 12 19:56 myfile.i
-rw-rw-r-- 1 ljb ljb   681 Jan 12 20:17 myfile.s

 生成了文件 myfile.s ,我们对比一下 myfile.s 与 myfile.i:

 此时,C语言已经变为了汇编语言,有效代码变为 42 行。

3、汇编

将汇编语言文件转换成可重定位目标二进制文件,这些二进制文件不可以被执行,文件的后缀为 .。对应到 Windows 系统中,相同类型文件的后缀为 .obj ,有几个源文件,就有几个 obj 文件。

汇编指令:

gcc -c [目标文件名] -o [生成文件名]

 -c : 从现在开始进行程序的翻译,汇编做完,就停下来。

我们对刚刚预处理形成的 myfile.s 文件进行编译:

[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ gcc -c myfile.s -o myfile.o
[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ ll
total 32
-rw-rw-r-- 1 ljb ljb   525 Jan 12 20:16 myfile.c
-rw-rw-r-- 1 ljb ljb 17086 Jan 12 19:56 myfile.i
-rw-rw-r-- 1 ljb ljb  1920 Jan 12 20:27 myfile.o
-rw-rw-r-- 1 ljb ljb   681 Jan 12 20:26 myfile.s

生成了文件 myfile.o ,我们打开该文件:

可以看到都是看不懂的乱码,这就说明该文件已经不是文本文件,而是一个二进制文件了。这个二进制文件是不可执行的。

4、链接

将我们自己形成的 .obj 文件和库文件进行某种合并,形成可执行程序。在我们进行链接的时候,把函数库对应的程序函数的地址拷贝到可执行程序里。

链接 / 编译指令:

gcc [目标文件名] -o [生成文件名]

我们对刚刚生成的 myfile.o 文件进行链接:

[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ gcc myfile.o -o myfile1
[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ ll
total 44
-rwxrwxr-x 1 ljb ljb  8440 Jan 12 20:40 myfile1
-rw-rw-r-- 1 ljb ljb   525 Jan 12 20:16 myfile.c
-rw-rw-r-- 1 ljb ljb 17086 Jan 12 19:56 myfile.i
-rw-rw-r-- 1 ljb ljb  1920 Jan 12 20:27 myfile.o
-rw-rw-r-- 1 ljb ljb   681 Jan 12 20:26 myfile.s

至此,我们就完成了一个程序翻译的完整过程,最终生成了可执行程序 myfile1

事实上,我们正常对一个程序进行编译,只需要执行 第四步:链接 的指令就可以,前三步都可省略,这里写出来是为了方便大家了解 gcc 编译的过程。

提示:

为了方便大家记住这些命令选项 与 后缀,我们可以来总结一下规律:预处理、编译、汇编的命令选项连起来是 -ESc ,与我们大家键盘最左上角的按键名字相同,而它们所生成的文件的后缀连起来是 .iso ,与镜像文件的后缀相同。这样是不是很好记忆了呢?

三、函数库

1、初识函数库

我们为什么能够在 Linux 下进行 C/C++ 代码的编写和编译呢?这是因为 Linux 系统默认已经携带了语言级别的 头文件 和 语言相应的库。

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

这些库所处的位置是 /usr/include/ ,我们可以使用 ls 指令看一下:

是不是有许多我们熟悉的头文件名称呢? 

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

ldd [可执行程序]

 ldd 指令可以帮我们检测这个可执行程序被形成的时候,都依赖了哪些库:

这个就是函数库。库分为两种,静态库 与 动态库,库也是文件。

静态库 一般以 lib 开头,以 .a 结尾。形如 libXXXXX.a 。

动态库 一般以 lib 开头,以 .so 结尾。形如 libXXXXX.so 。

这种后缀划分是 Linux 下特有的。在 Windows 下,静态库的后缀是 .lib ,动态库的后缀是 .dll

我们区分一个库的名字,是去掉它的前缀与后缀,看中间部分。

我们看一下上面图片中用红框圈起来的库函数是什么名字:

所以该库的名字是 c - 2.17 ,是C语言的C标准库。


实际上,现在我们学习 Linux 时所用的指令,有很大一部分都是使用C语言写的。

ls 指令为例:

我们使用 which 指令找到 ls 指令所在的位置:

[ljb@iZuf69tfiox41j76yf0416Z lesson5]$ which ls
alias ls='ls --color=auto'
	/usr/bin/ls

再使用 ldd 指令查看它所依赖的函数库:

可以看到也是C标准库。

2、动静态库

2.1、动态库

动态库是专门让编译器对用户的程序进行动态链接的。动态库又被称为 共享库 ,在连接的时候,如果是动态链接,就找到动态库,拷贝用户所需要的代码的地址到用户自己的可执行程序中相关的位置。动态链接成功,用户的程序还是依赖动态库,一旦动态库缺失,用户的程序便无法运行,操作系统中绝大多数指令也都无法再运行了。

以上是动态库的缺点,那么它有什么优点呢?

因为动态库可以做到被大家共享,所以代码真正的实现永远都是在库中,程序内部只有地址,比较节省空间。

2.2、静态库

静态库是专门让编译器对用户的程序进行静态链接的。在连接的时候,如果是静态链接,就找到静态库,拷贝用户所需要的代码到用户自己的可执行程序中。静态链接成功,用户的程序不再依赖任何库,程序可以独立运行。

以上是静态库的优点,那么静态库有什么缺点呢?

使用静态库的话,因为程序自身拷贝代码的问题,会比较浪费空间。

2.3、动静态库的选择

Linux 下默认使用的是 动态链接 和 动态库。我们接下来就来证明一下。

我们使用 file 指令来查看可执行文件 myfile1 的文件类型:

  ELF 是可执行程序的一种格式, dynamically linked 表明该可执行程序使用的是动态链接。


一般我们安装的操作系统,一般默认都只有动态库,没有安装静态库。那么如果我们想进行静态链接,需要先安装一下静态库:

sudo yum install -y glibc-static

安装完成后,我们就可以通过添加命令选项 -static 来使用静态链接了:

gcc [目标文件名] -o [生成文件名] -static

可以看到使用静态链接生成的可执行文件大小要比动态链接生成的大的多,这还仅仅只是一个非常简单的可执行程序,如果再复杂一点,这个差距会更大。因此我们选择使用动态链接

我们再来使用 ldd 指令 和 file 指令观察一下静态链接生成的可执行文件:

可以看到该文件没有依赖任何库,为静态链接。


关于 Linux 下编译器 gcc 与 函数库 的基本知识就讲到这里,希望同学们多多支持,如果有不对的地方欢迎大佬指正,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vLive虚拟直播,助力企业打造线上云年会

2023年农历春节临近,各大企业都纷纷开始筹备年会,面临员工分布各地无法同时参与、内容单一缺乏参与感等局限性,越来越多的企业选择做一场云年会替代传统线下年会。近日,蓝海彤翔集团举办2022年终总结表彰暨2023业务发展规划大会&a…

Transcational与Synchronized或Lock搭配使用导致并发问题

在多线程的情况下,我们经常会用到synchronized或者Lock来保证我们的线程安全。 但是当碰到Transcational之后又会碰撞出什么火花呢? 相信我,看完之后,你一定不会亏 首先回顾一下小知识点: 基于Transactional注解的是…

4.R语言【dplyr包】使用方法

b站课程视频链接: https://www.bilibili.com/video/BV19x411X7C6?p1 腾讯课堂(最新,但是要花钱,我花99😢😢元买了,感觉讲的没问题,就是知识点结构有点乱,有点废话)&…

黑马程序员Java教程学习笔记(二)

学习视频:https://www.bilibili.com/video/BV1Cv411372m 如侵权,请私信联系本人删除 文章目录黑马程序员Java学习笔记(二)数组概述数组定义方式一、访问、注意事项数组定义方式二,元素默认值规则数组遍历、元素求和数组…

HTML5+CSS3小实例:文本背景扫光效果

实例:文本背景扫光效果 技术栈:HTML+CSS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width…

【OpenGL学习】OpenGL环境配置

OpenGL环境配置 为了能够定义OpenGL上下文和创建用于显示的窗口&#xff0c;我们首先需要配置一些库来帮助我们实现&#xff0c;当前比较流行的用于创建窗口的库有GLUT&#xff0c;SDL&#xff0c;SFML和GLFW&#xff0c;其中网上的大部分教程使用的都是GLFW&#xff0c;因此我…

聊聊Pytorch2.0的新特性

一句话概括下&#xff0c;Pytorch2.0的功能介绍核心就是&#xff1a;torch.compile opt_module torch.compile(module)一行代码就能优化你的模型&#xff0c;优化后的模型和往常使用方式一样 速度会提升&#xff0c;比较重要的一点是&#xff1a;可以用于训练或者部署&#…

Grafana 告警接入飞书通知

Grafana 系列文章&#xff0c;版本&#xff1a;OOS v9.3.1 Grafana 的介绍和安装Grafana监控大屏配置参数介绍&#xff08;一&#xff09;Grafana监控大屏配置参数介绍&#xff08;二&#xff09;Grafana监控大屏可视化图表Grafana 查询数据和转换数据Grafana 告警模块介绍Graf…

带你从源码中分析关于vue(v2.7.10)的面试题

我们在面试的时候经常会被问到vue框架的原理类问题&#xff0c;我今天整理了一些常见问题和答案&#xff0c;希望有不正确之处还请指正。 1.new Vue时发生了什么 首先实例化一个对象&#xff0c;该对象执行init方法初始化生命周期等等&#xff0c;随后执行$mount方法开始生成v…

Modbus Slave缓冲区溢出漏洞CVE-2022-1068分析与复现

漏洞概述Modbus Slave是一个模拟工业领域通信协议Modbus从站的上位机软件&#xff0c;主要用于测试和调试Modbus从设备。该软件7.4.2以及以前的版本&#xff0c;在注册时&#xff0c;未对注册码长度进行安全检查&#xff0c;存在缓冲区溢出漏洞&#xff0c;导致软件崩溃。影响范…

在 Kubernetes 中部署并使用 KubeEdge

作者&#xff1a;马伟&#xff0c;青云科技容器顾问&#xff0c;云原生爱好者&#xff0c;目前专注于云原生技术&#xff0c;云原生领域技术栈涉及 Kubernetes、KubeSphere、KubeKey 等。 边缘计算在广泛制造业、工业、零售和金融等行业&#xff0c;随着云原生应用的兴起&#…

UDS诊断系列介绍07-2E服务

本文框架1. 系列介绍2E服务概述2. 2E服务请求与应答2.1 2E服务请求2.2 2E服务肯定响应2.3 2E服务否定应答3. Autosar系列文章快速链接1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议&#xff0c;即统一的诊断服务&#xff0c;是面向整车所有ECU的一…

Webpack打包图片-JS-Vue文件

打包图片等静态资源 资源模块 | webpack 中文文档 (docschina.org) 1、加载图片案例准备 为了演示我们项目中可以加载图片&#xff0c;我们需要在项目中使用图片&#xff0c;比较常见的使用图片的方式是两种&#xff1a; img元素&#xff0c;设置src属性&#xff1b;其他元…

基于Java jsp+mysql+Spring的汽车出租平台租赁网站平台设计和实现

基于Java jspmysqlSpring的汽车出租平台租赁网站平台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 …

蓝队攻击的四个阶段(二)

目录 一&#xff0c;漏洞利用工具 (1)WebLogic 全版本需洞利用工具 (2)Struts2 综合漏洞利用工具 (3)sqlmap 注入工具 (4)vSphere Client RCE 漏洞(CVE-2021-21972)利用工具 (5)Windows Print Spooler 权限提升漏洞(CVE-2021-1675) (6)Exchange Server漏洞组合利用(CVE-2…

JVM-【面试题】-带你了解对象的创建过程

本文介绍对象在jvm的创建过程该图是对象在jvm的创建过程一、类加载检查虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那…

图机器学习-图机器学习传统方法

图机器学习-图机器学习传统方法 最近在学习一些GNN相关的知识&#xff0c;想写一些笔记记录一下自己的学习过程&#xff0c;主要的学习资料为CS224W课程主页上面的资料和b站同济子豪兄的中文讲解。这篇博客是我2023年的第一篇博客&#xff0c;想以图机器学习中的传统方法作为博…

项目管理工具dhtmlxGantt甘特图入门教程(八):数据加载(三)

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理控件应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 这篇文章给大家讲解如何利用 dhtmlxGantt正确保存和显示任务的结束日期&#xff0c;本节将给你一个明确答案。 Dht…

异常-捕获业务异常踩坑记录

事情是这样&#xff0c;用了google的一个本地缓存框架&#xff0c;就是在查询数据的时候如果有就取缓存&#xff0c;没有就发http请求调接口&#xff0c;但是http请求也会有查询失败的时候&#xff0c;查询失败就会手动抛一个业务异常&#xff0c;然后我会在外层各种捕获异常&a…

三消游戏查找算法的原理和实现

本文首发于公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。今天这篇文章分享一下三消查找算法的原理和实现&#xff0c;其实三消的机制最早源于《宝石方块》…