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

news/2024/4/28 22:34:40/文章来源:https://blog.csdn.net/m0_71503225/article/details/137059466

目录

前言:快速认识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.luyixian.cn/news_show_1027224.aspx

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

相关文章

贪心算法--最大数

个人主页:Lei宝啊 愿所有美好如期而遇 本题链接https://leetcode.cn/problems/largest-number/description/ class Solution { public:bool static compare(int a, int b){return (to_string(a) to_string(b)) > (to_string(b) to_string(a));}bool operato…

MySQL创建表:练习题

练习题: 创建一个名为"students"的数据库,并切换到该数据库。 在"students"数据库中创建一个名为"grades"的表,包含以下字段: id: 整数类型 name: 字符串类型,学生姓名 subject: 字符串…

最小可行产品需要最小可行架构——可持续架构(三)

前言 最小可行产品(MVP)的概念可以帮助团队专注于尽快交付他们认为对客户最有价值的东西,以便在投入大量时间和资源之前迅速、廉价地评估产品的市场规模。MVP不仅需要考虑产品的市场可行性,还需要考虑其技术可行性,以…

计算机专业学习单片机有什么意义吗?

玩单片机跟玩计算机区别还是很大的, 单片机有众多的种类,每一种又可能有很多个系列.可以说单片机就是为了专款专用而生的.这样来达到产品成本的降低,这就是现在身边的很多的电子产品价格一降再降的原因之一.在开始前我有一些资料,是我根据网友给的问题精心整理了一…

安装paddle detection心得

一、安装PaddlePaddle conda create -n mypaddle python3.8 conda activate mypaddle python -m pip install paddlepaddle-gpu2.6.0 -i https://mirror.baidu.com/pypi/simple 请确保您的PaddlePaddle安装成功并且版本不低于需求版本。使用以下命令进行验证。 这是CUDA1…

SpringBoot项目启动成功,但是调用接口直接报NOT FOUND 404

问题描述 SpringBoot项目启动成功,但是调用接口直接报NOT FOUND 404 解决办法 启动类中ComponentScan(basePackages {“com.afclab”})中的扫包路径和项目路径不一样,导致扫不到Controller等组件,修改成和项目路径一样就可以解决&#xf…

8、鸿蒙学习-HAR

HAR(Harmony Archive)是静态共享包,可以包含代码、C库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。HAR不同于HAP,不能独立安装运行在设备上。只能作为应用模块的依赖项被引用。 一、创建…

206基于matlab的无人机航迹规划(UAV track plannin)

基于matlab的无人机航迹规划(UAV track plannin)。输入输出参数包括 横滚、俯仰、航向角(单位:度);横滚速率、俯仰速率、航向角速率(单位:度/秒);飞机运动速度——X右翼、…

小美的平衡矩阵(前缀和例题)

2024美团秋招,被这一题给难住了 美团校招笔试真题_Java工程师、C工程师_牛客网 题目: 解答: 这道题的关键点就是要计算出以某一点为矩阵右下角时,1的个数 我一开始是想着遍历,以某一点为起点(矩阵左上角&a…

Github万星项目lobe-chat,连接GPT4GPTs,平替chatgpt-plus

简介 Lobe Chat - 一个开源、高性能的聊天机器人框架,支持语音合成、多模态和可扩展的函数调用插件系统。支持一键免费部署您的私人 ChatGPT/LLM Web 应用程序。 项目地址: GitHub - lobehub/lobe-chat: 🤯 Lobe Chat - an open-source, mo…

稀碎从零算法笔记Day32-LeetCode:每日温度

算是引出“单调栈”这种数据结构,后面会用这个思想处理下接雨水问题 前言:单调栈模式匹配——题目中提到“求第一个最大/最小的元素” 题型:栈、单调栈、数组 链接:739. 每日温度 - 力扣(LeetCode) 来源…

Eclipse+Java+Swing实现斗地主游戏

一. 视频演示效果 java斗地主源码演示 ​ 二.项目结构 代码十分简洁,只有简单的7个类,实现了人机对战 素材为若干的gif图片 三.项目实现 启动类为Main类,继承之JFrame,JFrame 是 Java Swing 库中的一个类,用于创建窗…

深度学习500问——Chapter05: 卷积神经网络(CNN)(1)

文章目录 5.1 卷积神经网络的组成层 5.1.1 输入层 5.1.2 卷积层 5.1.3 激活层 5.1.4 池化层 5.1.5 全连接层 5.2 卷积在图像中有什么直观作用 5.3 卷积层有哪些基本参数 5.4 卷积核有什么类型 5.5 二维卷积与三维卷积有什么区别 卷积神经网络是一种用来处理局部和整体相关性的计…

Unity图集编辑器

图集编辑器 欢迎使用图集编辑器新的改变编辑器图片 欢迎使用图集编辑器 Unity图集操作很是费劲 无法批量删除和添加图集中的图片 新的改变 自己写了一个图集编辑器 客: 支持批量删除 左键点击图片代表选中 右键点击图标定位到资产支持批量添加 选中图片拖拽到编…

基于Spring boot + Vue协同过滤算法的电影推荐系统

末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发 更多项目:CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶路,不能慢一步。 目录 一、项目简介 二、开发技术与环…

iOS开发进阶(十一):ViewController 控制器详解

文章目录 一、前言二、UIViewController三、UINavigationController四、UITabBarController五、UIPageViewController六、拓展阅读 一、前言 iOS 界面开发最重要的首属ViewController和View,ViewController是View的控制器,也就是一般的页面,…

蛋糕店怎么弄一个微信小程序_开启蛋糕店新篇章

微信小程序,开启蛋糕店新篇章——甜蜜触手可及 在这个数字化、智能化的时代,微信小程序以其便捷、高效的特点,成为了众多商家与消费者之间的桥梁。对于蛋糕店而言,拥有一个专属的微信小程序,不仅可以提升品牌形象&…

HTTP状态 405 - 方法不允许

方法有问题。 用Post发的请求&#xff0c;然后用Put接收的。 大家也可以看看是不是有这种问题 <body><h1>HTTP状态 405 - 方法不允许</h1><hr class"line" /><p><b>类型</b> 状态报告</p><p><b>消息…

Gitlab CI---could not read username for xxx: no such device or address

0 Preface/Foreword 项目开发中&#xff0c;经常会使用第三方的算法或者功能&#xff0c;那么就需要把对应的repo以子模块的方式添加到当前repo中。 添加命令&#xff1a; git submodule add <URL> 1 问题表现 子模块添加成功&#xff0c;但是GitLab CI阶段&#xff…

2024最新版克魔助手抓包教程(9) - 克魔助手 IOS 数据抓包

引言 在移动应用程序的开发中&#xff0c;了解应用程序的网络通信是至关重要的。数据抓包是一种很好的方法&#xff0c;可以让我们分析应用程序的网络请求和响应&#xff0c;了解应用程序的网络操作情况。克魔助手是一款非常强大的抓包工具&#xff0c;可以帮助我们在 Android …