【Linux】 gcc(linux下的编译器)程序的编译和链接详解

目录

前言:快速认识gcc

1. 程序的翻译环境和执行环境

2.编译和链接

2.1翻译环境

2.2编译环境

1. 预处理  gcc -E指令 test.c(源文件) -o test.i(生成在一个文件中,可以自己指定) 预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

编译 选项 gcc -S test.c 编译完成之后就停下来,结果保存在test.s中。

3. 汇编 gcc -c test.c 汇编完成之后就停下来,结果保存在test.o中。 

2.3 运行环境 

3.动静态库

3.1铺垫

3.2 动静态库的链接

3.2.1动态库理解

3.2.2 静态库理解

3.3 gcc某认链接动态库

报错/usr/bin/ld: cannot find -lc

​编辑

解决方式搜索关键字:cetenos 7 c/c++静态库下载 

4.语言的自举过程 

先有语言还是现有编译器?

5.结尾


前言:快速认识gcc

gcc是linux下的一款编译器,可以在指令级别将代码编译形成可执行程序

格式 gcc [ 选项 ] 要编译的文件 [ 选项 ] [ 目标文件】

我们手动编写一个简单的程序

使用指令gcc 文件名进行编译

也可以在底行模式中直接编译

生成一个a.out的可执行程序

./a.out运行这个程序

这是gcc的一个快速认识

关于gcc其他的指令

-E 只激活预处理 , 这个不生成文件 , 你需要把它重定向到一个输出文件里面
-S  编译到汇编语言不进行汇编和链接
-c  编译到目标代码
-o 文件输出到 文件
可以控制生成的可执行程序名字不叫a.out,
gcc test.c -o mybin,此时目录下的mubin就是一个可执行文件。可以./运行
也可以: gcc -o mybin test.c
 
-static 此选项对生成的文件采用静态链接
-g  生成调试信息。 GNU 调试器可利用该信息。
-shared  此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库 .
-O3 编译器的优化选项的 4 个级别, -O0 表示没有优化 ,-O1 为缺省值, -O3 优化级别最高
-w  不生成任何警告信息。
-Wall 生成所有警告信息。
—D   后面跟宏, -D VER=1,
给编译器传递不同的宏值示实现对代码的裁剪,也叫作条件编译

编译器专业版本和社区版本:收费版本和免费版本。

凡是免费版本有的,专业版也有,专业版提供的技术更多。维护这个产品的时候是维护一份,使用预编译对代码进行裁剪就可以生成不同版本(指社区版本和专业版本)的软件

有时在编写程序的时候:我们往往会写下这种代码:

#ifdef  __CDDE_H

#define_CODE_H_

XXXXX

#endif        

这段代码的作用是为了防止头文件被重复包含

那么原因是:头文件展开就是头文件被拷贝到源文件中,第一次拷贝没有被定义,都二次拷贝就是被定义了,就不会再编译剩下的代码。

g++ 也是一款编译器,与gcc不同
我们编写一段c++的代码

我们使用gcc编译一下这个文件

c++的代码使用g++编译器来编译,C语言也可以用g++来编译。 

1. 程序的翻译环境和执行环境

在ANSI C(c标准)的任何一种实现中,存在两个不同的环境。

  • 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  • 计算机是能够执行二进制指令的,但是我们写的C语言代码是文本信息,计算机不能直接理解,翻译环境将C语言代码翻译为二进制指令,放在了可执行程序中。
  • 第2种是执行环境,它用于实际执行代码 执行的是二进制代码

2.编译和链接

2.1翻译环境

组成一个程序的每个源文件通过编译过程(都单独经过编译器生成目标文件 。obj)分别转换成目标代码(object code)。 这个过程叫做编译。

每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。

链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人 的程序库,将其需要的函数也链接到程序中,这个过程叫做链接。

链接库说明:库函数编译放在了静态库中

我们的vs中集成了编译器(cl.exe)和链接器(link.exe)+调试器,所以程序执行起来自动链接库

上述过程在具体的项目中:

两个.c 文件

 生成两个目标文件

经过连接形成一个可执行程序

这是笼统的,接下来就看看详细过程

从C语言代码到可执行程序经过两个大的过程:

编译和链接

vs 集成开发环境不方便看逐个过程 ,使用linux下的gcc环境来观察

2.2编译环境

1. 预处理  gcc -E指令 test.c(源文件) -o test.i(生成在一个文件中,可以自己指定) 预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

在vim中编写源文件

在test.i文件中我们可以发现,不仅仅有我们自己写的代码,还多出了800行左右的代码

这些代码就是来自我们包含的头文件《stdio.h》

然而对于为什么右边有900多行代码,左边只有八百多行:

注释和#define的语句没有了

 

所以我们预编译阶段处理的事:

①#include 头文件的包含,将头文件和我们自己写的代码整合在一起

②注释的删除

③#define 符号的替换

这些都是一些文本操作 

编译 选项 gcc -S test.c 编译完成之后就停下来,结果保存在test.s中。

 这里面存储的是汇编指令,这个阶段是将C语言代码翻译成为了汇编语言,并且做了词法的分析、语义分析和符号的汇总。

3. 汇编 gcc -c test.c 汇编完成之后就停下来,结果保存在test.o中。 

这个阶段将汇编语言翻译称为了二进制文件,同时形成了符号表

目前这个二进制文件不可以被执行:因为我们的头文件中包含了很多函数的接口,比如我们的输入输出函数,printf、scanf等,都需要找到对应的函数才可以,所以目前只是将函数名等做了一个汇编整理。

我们修改一个更为复杂一点的代码来看一下更为详细的过程:

对这段代码进行编译,生成目标文件和可执行程序

虽然还是看不懂的二进制指令,但是可以看出有规定的ELF格式:

linux下,gcc编译产生的目标文件和可执行程序,都是按照ELF这种文件的格式来存储的

使用readelf 工具可以识别elf格式的文件

将代码分成了一段一段的进行处理:头部等等.......

我们可以发现,在编译阶段,函数名和全局变量这些符号就做了汇总:

具体图解如下: 

2.3 运行环境 

程序执行的过程:

  • 1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  • 2. 程序的执行便开始。接着便调用main函数
  • 3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
  • 4. 终止程序。正常终止main函数;也有可能是意外终止

3.动静态库

3.1铺垫

ldd命令可以查看一个可执行程序依赖的库文件

 这里就可以看到我们的当前可执行文件依赖的是/lib64/lib.so.6这个路径下的库

这就是我们C语言的库

那么我们所说的库一般分为两类:动态库和静态库 

在linux中动态库以.so为后缀,静态库以.a为后缀

在windows下:动态库以.dll为后缀,静态库以.lib为后缀。

有时我们运行软件时可能由于操作不当或者错误杀毒,运行是报警告动态库缺失

原因是:

某些杀毒软件会扫描系统的库文件,有些病毒会将.dll这个库删掉,然后自己伪装成对应的库,就是在原有的库中新增加了一些代码,当我们编译运行的时候就会进入到库中就会执行到这些病毒代码,就会导致信息泄露,这种就叫做对库进行恶意替换,所以很多杀毒软件都要扫码库文件,可能杀毒文件也有bug就会删除掉用户的正常的库,导致后续使用出问题。

如何知道我们的程序使用的是什么样的库呢

所有的库都是用lib开头,将前缀lib去掉,然后将.so包括.so后续内容去掉,就可以看到,我们使用的是c库。

为什么我们的linux或者vs支持我们进行C语言的开发?

原因就是,linux已经某认给我们提供了C语言的头文件

 

所以一个开发平台必须要提前在系统中安装至少语言的标准头文件和库文件。windows中安装vs就是因为没有某认的C语言环境。 

3.2 动静态库的链接

那么我们所说的库一般分为两类:动态库和静态库 

在linux中动态库以.so为后缀,静态库以.a为后缀

在windows下:动态库以.dll为后缀,静态库以.lib为后缀。

与动态库的链接叫做动态链接,与静态库的链接叫做静态链接。

库是个文件

linux下的动态库:

l

C语言源文件变成库就是将源文件编译成.o文件,将.o文件打包变成库文件,所以链接的时候就是将我们的.o文件和库的.o文件合并。

3.2.1动态库理解

动态库就是在可执行程序运行代码时,如果要运行比如库函数,就需要找到库文件,这个叫进入库中进行库调用,而后,找到我们需要的那段代码并执行,这个过程叫做库方法,执行完后返回继续我们的程序。动态库可以被多个程序公用,一但缺失,大家都会崩溃。

优点:每个人的程序中只有调用函数的地址,调用链接才会实现实例化,大家都用一个库,比较节省资源,不会出现太多重复代码。 加载到内存中就会节省内存资源,别人网络下载的时候,下砸周期就会变短,网络资源也会节省。

所以动态库特点:被多个程序共同使用,一但缺失,所使用这个库的所有程序都不可在运行

这也是一个缺点:程序对库的依赖性比较强。

误操作:对库升级覆盖等等导致库丢失出问题,就会导致程序大面积崩溃。

其次,库调用的时候会涉及到地址的保存,和跳转,调用周期相比于静态库会稍微长一点,效率低一些。

我们的linux中指令常用的ls pwd等等都是依赖于我们的C语言库

3.2.2 静态库理解

静态库就是将程序所需要的调用的库函数具体内容拷贝一份到自己的可执行程序中。此时就叫做静态链接。从此我们的程序不再依赖三方库。同类型平台都可以直接运行使用。

缺点:代码拷贝,可执行程序体积比较大,资源会浪费(磁盘、内存、网络)

所以允许拷贝的库就是静态库,运行关联的库就叫做动态库。两个库是两个文件,两个库在实现的时候,编址的方式也不一样,动态库的方法不能直接拷贝到可执行文件。所以是两个文件

我们的可执行程序都是自己的代码+库的代码构成。那么库将常用的函数实现打包,大大提高了我们开发的效率

3.3 gcc某认链接动态库

我们编译运行一个程序

 

此时生成的可执行文件是链接到动态库的

当我们需要静态链接,就需要执行以下指令:

 

文件正常运行

 

当我们ldd时:

显示我们没有动态连接

file查看这个可执行文件,staticlink 静态链接

所以gcc默认采用动态链接。 

这里我们程序中只有一个printf,二者的大小区别已经很明显

我们的centos默认是没有装我们的静态库的

当我们运行指令gcc -static mytest.c -o mybinsta

报错
/usr/bin/ld: cannot find -lc

就是因为没有C语言静态库,因为某认gcc链接动态库 

解决方式搜索关键字:cetenos 7 c/c++静态库下载 

执行指令

 yum install -y glibc-static

yum install -y glibc++-static
 

 

这是在root用户下,普通用户注意提权。

安装好后就可以使用了

 


 

4.语言的自举过程 

在早期的计算机中,或者到现在为止,计算机能识别的都是二进制的语言,而早期的计算机是通过打孔纸袋来识别信息,有孔的地方就是1,没有孔的地方就是0.

而后诞生了汇编语言,由于汇编语言不能直接在计算机上执行,所以诞生了编译器,(而后才诞生了操作系统,linux就是通过汇编语言就行编写的,第一版),由于对汇编语言的使用不流畅,所以在汇编语言的基础上诞生了C语言。C语言也需要对应的编译器,后续由于对于面向对象这种思维方式编程常用,所以c++等面向对象的语言诞生。而像python/php/shell/java等都是解释型或者半解释型语言,都要有自己的解释器,不够这些解释器都是由C语言写的。那么:

先有语言还是现有编译器?

比如现在有汇编语言但是没有编译器(是特指汇编语言编写的编译器),那么第一个将汇编语言编译成二进制的编译器肯定不可能是汇编语言写的,同理第一个将C语言翻译成汇编语言的编译器也不可能是C语言写的。一定是先有语言才有这个语言编写的编译器,比如现在有了汇编语言,肯定是没有将汇编语言编译的编译器的,但是我们可以用二进制的语言写一个汇编编译器。(怎么理解:假设汇编语言是我们当前最新的语言,但是编译器也是一款软件,也是需要语言编译形成,那么汇编语言刚诞生,我们可以使用语言来写软件,但是也需要编译才可以形成这个汇编语言形成的编译器呀,所以此时不可能有汇编语言写的编译器,但是可以用二进制的语言写一款汇编编译器。来编译汇编语言代码,形成软件。那么就有了一款用汇编语言编写的编译器,不过这款编译器从汇编代码变成软件是由二进制编译器来生成的。)然后汇编语言编译器自我迭代变得越来越好,这个过程就叫做语言的自举过程。汇编语言到C语言之间也是这样。

C语言出现--》用低级语言(汇编语言)写一个c编译器---》C语言代码变成软件

用C语言写一个编译器--》经过低级语言写的编译器翻译执行---》形成C语言写的编译器

那么自然的,从C语言直接翻译到二进制语言是没有C语言翻译到汇编语言,再从汇编语言翻译到二进制好,所以才有了预处理,编译、汇编、链接等过程。

所以人工智能最初没有,人为写一个人工智能程序,人为训练,然后未来就会演变成人工智能训练人工智能。也是软件自举的原理,所以有chat-gpt各种版本。

5.结尾

上述就是今天分享的内容,如果大家觉得有用,创作不易,希望收获三连。我是Nicn,欢迎一起交流学习。

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

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

相关文章

LeetCode 1027——最长等差数列

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 假设我们以 f[d][nums[i]]表示以 nums[i] 为结尾元素间距为 d 的等差数列的最大长度,那么,如果 nums[i]-d 也存在于 nums 数组中,则有: f [ d ] [ n u m s [ i ] ] …

解决vim中NERDTree图标是问号或者乱码问题

解决vim中NERDTree图标是问号或者乱码问题 乱码信息如图解决办法1. 安装字体下载字体安装字体Ubuntu系统Windows11系统 2. 控制台修改字体Ubuntu系统Windows11系统 乱码信息如图 Ubuntu系统上的情况 使用windows控制台连接的情况 解决办法 1. 安装字体 下载字体 在nerd f…

51单片机学习9 串口通讯

51单片机学习9 串口通讯 一、串口通讯简介UARTSTC89C51RC/RD的串口资源 二、51单片机串口介绍1. 内部结构2. 寄存器(1)串口控制寄存器SCON(2)电源控制寄存器PCON 3. 计算波特率4. 串口配置步骤 三、 开发示例1. 硬件电路2. 代码实…

网络面试——浏览器输入url到显示主页的过程

浏览器输入URL到显示主页的过程通常可以分为以下步骤: 1. **URL解析**: - 当用户在浏览器的地址栏中输入URL时,浏览器会首先对该URL进行解析。 - 解析URL包括识别协议(例如HTTP、HTTPS)、主机名(例如…

YOLOv5-小知识记录(一)

0. 写在前面 这篇博文主要是为了记录一下yolov5中的小的记忆点,方便自己查看和理解。 1. 完整过程 (1)Input阶段,图片需要经过数据增强Mosaic,并且初始化一组anchor预设; (2)特征提…

MSA7T10 DVBT2高清机顶盒方案

一、方案描述 MSA7T10系列芯片是Mstar推出的极富竞争力的DVB-T2机顶盒FTA方案,芯片内置64MB DDR2和T2解调器,支持T2 1.3.1规范,支持HEVC,H.264,MPEG高清视频,支持PVR/Timeshit功能,支持各种多媒…

曲线生成 | 图解Reeds-Shepp曲线生成原理(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是Reeds-Shepp曲线?2 Reeds-Shepp曲线的运动模式3 Reeds-Shepp曲线算法原理3.1 坐标变换3.2 时间翻转(time-flip)3.3 反射变换(reflect)3.4 后向变换(backwards) 4 仿真实现4.1 ROS C实现4.2 Python实现4.3 Matlab实现 0 专栏介绍 &#x1f5…

如何利用社媒群组如何高效开发国外客户

现在社媒营销也是越来越流行了,很多外贸人都开始做社媒营销。社媒营销相对来说是比较有温度的一个营销,因为大部分社媒平台都支持在线聊天,触达的即时性是比较高的,效果也比传统的一些方法要好一些。 当然做社媒也是有难度的&…

西藏实景三维技术研讨交流会成功举办

2024年3月21-22日,西藏自治区“实景三维技术研讨交流会”在拉萨成功举办。 本次会议由西藏自治区自然资源厅、自然资源部重庆测绘院指导,西藏自治区测绘学会、西藏自治区地理信息产业协会主办,武汉大势智慧科技有限公司(后简称“…

数据库-索引快速学

索引 当表中数据量庞大时,往往搜索一条数据就会耗费很长的时间等待 索引是帮助数据库高效获取数据的数据结构 create index 索引名 on 数据表名(字段名);为该表下的某一字段创建索引,检索耗时会大大的减小 索引的优缺点 优点&…

【Python BUG】CondaHTTPError解决记录

问题描述 CondaHTTPError: HTTP 429 TOO MANY REQUESTS for url https://mirrors.ustc.edu.cn/anaconda/pkgs/free/win-64/current_repodata.json Elapsed: 00:26.513315 解决方案 找到用户路径下的 .condarc文件,建议用这个方法前和我一样做个备份,方…

python中类的导入与使用

1、类的介绍 与C中面向对象思想类似,有时候为了方便,需要专门创建一个类,将相关的函数全部写入到该类中,方便后续创建对象,再使用类中函数。那么如何创建完类,在其他文件中使用类中函数,这是这篇…

Python Flask框架 -- flask-migrate迁移ORM模型

# 之前使用的这个db.create_all()很有局限性,它不能把在class里修改的东西同步上数据库,所以不用了 # with app.app_context(): # 请求应用上下文 # db.create_all() # 把所有的表同步到数据库中去 例如,在User类中增加一个email字段&…

STM32和GD32内部时钟与外部时钟讲解

STM32F103为例: 1. 当 HSI 被用作 PLL 时钟输入时,可以实现的最大系统时钟频率为 64 MHz。 2. 要使 USB 功能可用,必须同时启用 HSE 和 PLL,并使 USBCLK 运行在 48 MHz。 3. 要实现 ADC 转换时间为 1 s,APB2 必须为 14 MHz、28 MHz 或 56 MHz。 ①. HSE = 高速外部时钟信号…

[linux初阶][vim-gcc-gdb] OneCharter: vim编辑器

一.vim编辑器基础 目录 一.vim编辑器基础 ①.vim的语法 ②vim的三种模式 ③三种模式的基本切换 ④各个模式下的一些操作 二.配置vim环境 ①手动配置(不推荐) ②自动配置(推荐) vim是vi的升级版,包含了更加丰富的功能. ①.vim的语法 vim [文件名] ②vim的三种模式 命令…

爬取搜狗翻译项目实例

视频中讲解的是百度翻译,但是视频中的方法现在已经不适用了,因为他们对 URL 的参数进行了修改,导致没法直接修改参数来爬取对应的翻译结果,这里我使用搜狗翻译来做演示,原理是一样的。 我们搜索的关键字会返回在 URL 中…

家用超声波清洗机高端品牌推荐!4款值得入手的热门超声波清洗机

急着洗眼镜的朋友先不要慌,虽然洗眼镜是日常生活中最常见的操作,但是在清洗眼镜方面也是有讲究的,不是随随便便把眼镜擦一下就算清洁干净了!因为我们拿眼镜布擦眼镜的时候,布料粗糙的微粒就会跟砂纸一样打磨着镜片&…

【python】flask模板渲染引擎Jinja2中的模板继承,简化前端模块化开发

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

什么是Prompt Tuning?

本文是观看视频What is Prompt Tuning?后的笔记。 大语言模型(如ChatGPT )是基础模型,是经过互联网上大量知识训练的大型可重用模型。 他们非常灵活,同样的模型可以分析法律文书或撰写文章。 但是,如果我们需要用其解…

cocos3.0 关于UI组件学习

Sprite 图片:官方文档 Size Mode: 1.Raw:原始大小 2.TRIMMED: 默认,会裁切原始图片透明像素 3.Custom:自定义,只要修改ContentSize,会自动设置 Type 1.Simple:普通,会铺满,一张图。 2.Sliced…