Linux编译器——gcc/g++使用

前言:

 在上一篇,我们学习了关于文本编辑器 vim 的全部知识,今天给大家带来的是关于Linux编译器—gcc/使用的详细介绍。


本文目录

 (一)温习程序的产生的过程

1、前言

2、程序的产生过程

3、🌜初步认识 gcc🌛

a) gcc的基本概念

b)gcc的基本特点

4、使用方法💻

(二)逐过程讲解🔥

1、 🤜 预处理 🤛 

2、🤜   编译   🤛 

3、🤜   汇编   🤛 

4、🤜   链接   🤛 

5、🔥巧记选项🔥

(三)动静态库的理解

1、前言摘要

2、ldd 指令

3、动静态库的理解

a)概念

b)区别

c)实例演示

d)总结动静态库的优缺点

(四)总结


(一)温习程序的产生的过程

1、前言

 通过之前的学习,我们可以知道在 Linux 下编写C\CPP 程序时,在完成 .C 或 .CPP 文件的编写后,我们通常直接 gcc 或 g++ 后接文件名,就可以在当前文件夹下生成 a.out 可执行文件, 之后输入 ./a.out 即可执行该二进制可执行文件。


  但实际上C语言程序从编写到运行,这期间的经历并不是这么简单,接下来我就带领大家对其探索一番,这期间具体有哪几个步骤?


2、程序的产生过程

从之前的知识来说,我们应该都知道程序的翻译经过几个阶段。我们会历经三个步骤,分别是:【预处理阶段】——>【编译阶段】——>【链接阶段】。但是如果我们分的更细一点,其实我们可以分成四个步骤:

通常 gcc 命令后面不加选项的话,就会默认执行 预处理、编译、汇编、链接所有步骤,若程序没有错误的话,我们就可以得到一个可执行文件,默认为 a.out, 也就是上述我代码中出现的。


3、🌜初步认识 gcc🌛

有了上述的铺垫之后,接下来我们讲讲什么是 gcc吧!!先让大家有了认识,以便我们后序的深入学习。

a) gcc的基本概念

  • gcc 的全称是 GNU Compiler Collection,它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器(GNU C Compiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。

b)gcc的基本特点

  • gcc是一个可移植的编译器,支持多种硬件平台。例如ARM、X86等等。
  • gcc不仅是个本地编译器,它还能跨平台交叉编译。所谓的本地编译器,是指编译出来的程序只能够在本地环境进行运行。而gcc编译出来的程序能够在其他平台进行运行。例如嵌入式程序可在x86上编译,然后在arm上运行。
  • gcc有多种语言前端,用于解析不同的语言。
  • gcc是按模块化设计的,可以加入新语言和新CPU架构的支持。
  • gcc是自由软件。任何人都可以使用或更改这个软件。

4、使用方法💻

gcc 是一个常用的 C 语言编译器,可以将源代码转换成可执行程序。 使用 gcc 编译器需要以下步骤:

  1. 编写 C 语言源代码文件,以 .c 作为文件扩展名。
  2. 打开终端或命令行界面。
  3. 进入源代码所在的目录。
  4. 输入命令 ,其中 是你要编译的文件名(不包括扩展名), 是你想要得到的可执行文件名(不包括扩展名)。
  5. 格式为:gcc <源代码文件名>.c -o <输出文件名><源代码文件名><输出文件名> 
  6. 回车运行命令,等待编译完成。
  7. 检查是否生成了可执行文件,如果成功则可以运行该程序。

例如,编译名为 的 C 语言源代码文件,并将其输出到名为 的可执行文件中,可以使用以下命令:hello.c hello

gcc hello.c -o hello
//加入-o选项的意义在于你可以指定输出二进制文件的名字

(二)逐过程讲解🔥

有了上述的前情铺垫之后,接下来我们具体的讲讲各个阶段到底是是怎么样的!!

1、 🤜 预处理 🤛 

首先第一步就是预处理阶段,在这个阶段主要主要执行的包括以下四个步奏:

  • 💨头文件展开

  • 💨条件编译

  • 💨宏替换

  • 💨 去注释

举例说明:

其中预处理阶段是把代码中的【#】开头的命令进行相应的处理,例如:

  • 【#include】,就是去找到对应的头文件,就是直接把头文件的内容复制过来,它生成的结果也是一个文本文件,通常用.i作后缀
  • 【#define】就是去替换代码中所有宏定义部分的内容,这一步没有任何程序转化发生,完全是在文本层面的。

 💥gcc执行指令

gcc -E test.c -o test.i
  • 例如,我们现在写了这样的一个【test.c】的文件
  1 #include<stdio.h>                                                                    
  2 #define MAX 1000                                                                     
  3                                                                                      
  4 int main()                                                                           
  5 {                                                                                                                       
  6                                                                                      
  7   printf("hello world\n");                                                           
  8                                                                                      
  9                                                                                      
 10   int m = MAX;                                                                       
 11   printf("%d\n",m);                                                                                                                                              
 12                                                                                                                      
 13   printf("hello world\n");                                                      
 14                                                                                      
 15 //  printf("hello world\n");                                                         
 16 //  printf("hello world\n");                                                         
 17 //  printf("hello world\n");                                                    
 18 //  printf("hello world\n");                                                            
 19 //  printf("hello world\n");                                                         
 20 //  printf("hello world\n");                                                         
 21 //  printf("hello world\n");                                                    
 22                                                                                                                                                                      
 23                                                                                                                      
 24                                                                                      
 25  return 0;                                                                                         
 26 }                                                                                    
     

经过 命令之后就变成了这样

 💨选项

  • “-E”:该选项的作用是让 gcc 在预处理结束后停止编译过程;
  • “-o”:是指目标文件,“.i”文件为已经过预处理的C原始程序;

2、🤜   编译   🤛 

预处理阶段过后紧接着就是编译阶段。这个阶段处理的就是c语言的汇编语言,它主要处理的包括以下:

  • 💨词法分析
  • 💨语法分析
  • 💨语义分析
  • 💨以及之后的优化

注意:

  • 编译阶段是整个程序从C到机器语言翻译过程的核心,其中最关键的【词法分析】——【语法分析】——【语义分析】——【优化等其他操作】, 其实就是在这个阶段执行的。

 💥gcc执行指令

gcc -S test.i -o test.s

👉 其实【gcc】在执行编译命令的时候会带上预处理,然后不保存过渡用的预处理出来的【.i】文件,所以编译时候的输入还是你写的【.c】文件,如果想看一看预处理结果的话才用【-E】指令;

👉 其次如果我们直接用原始【.c】文件来编译一下也可以,用刚生成的【.i】文件编译也是可以的,命令是【gcc -S test.i -o test.s】(我这里默认的是从上次结束的地方继续执行)

👉 最终结果是一个汇编程序的文件,注意这里输出的仍然是一个文本文件。

 💨选项:

  • “-S”;来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

3、🤜   汇编   🤛 

编译阶段过了之后,紧接着就是汇编的执行阶段。在这个阶段,它做的主要有以下的事情:

💨将汇编指令转换为二进制文件

💨 形成符号表

 💥​​​​​​​gcc执行指令

gcc -c test.s -o test.o

👉 汇编就是把编译出来的汇编文件打包成一个二进制文件,里面存的都是机器指令.gcc的命令是gcc -c test.s -o test.o, 得到的结果是个【.o】文件,这个文件是不能用人类语言解读的,打开发现是一堆乱码

👉 此时当我们想来试着执行一下这个目标文件时,不过发现没有【x】可执行的权限,于是使用chmod做一个提权的操作。

👉 但是系统却说【cannot execute binary file】因为这是一个二进制文件,对于二进制文件来说是不可以被执行的。

💨选项:

  • “-c”;就可看到汇编代码已转化为“.o”的二进制目标代码了


4、🤜   链接   🤛 

最后,即是链接操作了,在这一步主要做的事是:

  • 💨将我们自己程序执行形成的【.obj】文件与库文件某种合并,形成可执行程序

💥​​​​​​​gcc执行指令

gcc test.o -o test

👉 检查刚才的【.o】文件,查看它引用的其他【.o】文件,比方说【printf】函数就是C语言的库函数,她在一个单独的【printf.o】文件里,这个文件在 gcc 的目录里面,和我们现在创建的工程没有关系,所以看不见;

👉 但是它会去库中找这个文件,所以链接就是找到它,然后把他们集成到一个可执行程序里

最后,我们打印一下最后的文件,看是否能够正常的运行并且输出对应的结果:


5、🔥巧记选项🔥

⌨️命令选项 :【-E】 【-S】 【-c】——>键盘上左上角的键(注意 s 要大写)

⌨️文件后缀 【.i】   【.s】  【.o】——>iso为镜像文件的后缀

文件后缀:

 命令选项:


(三)动静态库的理解

1、前言摘要

此时,不知道大家知不知道我们为什么能够在【Linux】在进行C、C++代码的编写和编译呢?

首先,我们先编写【.Cpp】程序试试看在【Linux】上是否能够运行!

运行结果如下:

👉  上述我们可以发现,对于【.cpp】程序一样是可以的。那么到底是为什么呢?是怎么实现的呢?

👉  我们先来看看系统中的头文件所在目录,然后就可以发现我们熟悉的头文件名【stdio.h】等

👉  头文件是告诉我们使用的方法,通过头文件的方式把方式告诉我们,其次也在告诉编译器,头文件是否有,只要有头文件就有源文件。


2、ldd 指令

 ldd本身不是一个程序,而仅是一个shell脚本:ldd可以列出一个程序所需要得动态链接库

我们可以用which命令找到ldd的位置:

 格式:

ldd(选项)(参数)
  • ldd命令通常使用 "-v" 或 "--verbose" 选项来显示所依赖的动态连接库的尽可能的详细信息。

👉   紧接着我们就可以去看看刚才【g++】之后最终链接后形成的【a.out】这个可执行程序都依赖了哪些库。

🔥 注意: 

在 ldd 命令打印的结果中:

“=>” 左边的表示该程序需要连接的共享库之 so 名称;

            右边表示由 Linux 的共享库系统找到的对应的共享库在文件系统中的具体位置。

因此,在此就解答了上述的问题为什么可以在【linux】下编写代码了!!!


此时,有衍生出来了一个问题——>那就是大家知道我们平时写代码的【vs2022】啊还是【vs219】或者其他的,当我们刚开始安装它的时候,实际上帮我们完成的最重要的工作是什么吗?

  • 其实就是帮我们下载并安装语言的头文件和库文件!!!

 紧接着,我们在【linux】下是不是纯手工的方式进行操作啊,用的全是指令那么这些指令怎么来的呢?

我举几个例子带大家见识见识:

  • ls指令

  •  which指令

  •  pwd指令

👉  综上所述:

我们可以看出在【linux】下,不管是 指令、工具、还是程序 等都是通过C语言写出来的!!!


3、动静态库的理解

a)概念

首先,在学习之前,我们肯定地需要知道什么叫做动静态库。因此,第一步我们先认识静动态库:

 💨 静态库:

  • Linux下,以 .a 为后缀的文件。程序在编译链接的时候把库的代码链接到可执行文件中。
  • 程序运行的时候将不再需要静态库。
  • 本质是在编译时把静态库中的代码(不是一次性加载,而是分页加载)复制到了进程的的代码区中。


💨  动态库:

  • Linux下,以 .so 为后缀的文件。程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。

b)区别

  1、🌜 代码被载入的时刻不同🌛

  • 静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。
  • 动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。
  • 不同的应用程序如果调用相同的库,那么在内存中只需要有一份该动态库(共享库)的实例。

  2、🌜大小与共享的差异🌛

  • 静态情况下,把库直接加载到程序中;
  • 而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。

  2、🌜程序编译的差异🌛

  • 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库
  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在

c)实例演示

在常用的指令中我们有说到过【file】指令,这个指令的作用是可以用来查看一个文件的类型,接下来我们就去瞧瞧这个动态的可执行文件

  •  💨因此,我们不难看出这个可执行文件是经过动态链接生成的。

那这时就有小伙伴要问了?那我们如何实现静态链接呢? 其实很简单,只需在最后加上 【-static】即可。

但是如果大家没有安装静态库,此时你在你在执行以下代码的话就会报错(云服务器默认使用的是动态库)

  • C静态库安装    : (sudo) yum install -y glibc-static
  • C++静态库安装: (sudo) yum  -y install libstdc++-static

演示如下:

所以大家知道为什么云服务器默认是安装的动态库了吧!!!


d)总结动静态库的优缺点

💥 静态库

  • 优点: 程序运行的时候将不再需要静态库
  • 缺点: 生成的可执行程序比较大。如果多个使用静态链接生成的程序同时运行会占用大量的内存空间

💥 动态库

  • 优点: 动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
  • 缺点: 程序运行的时候依赖动态库

有关动静态库的更多知识,我们将在后面进行补充讲解!


(四)总结

到此,本文的内容便讲解完毕!最后,我们对本期内容做个小结!!!

  • 首先,我们回顾了程序产生的过程,并在此情况下引出了关于 【gcc】;
  • 紧接着我们对程序产生的步奏进行具体的讲解,让大家知道程序是如何一点点的变为最终的可执行程序的;
  • 最后,我们引出了关于Linux下库的概念,给出了关于【静态库】和【动态库】的概念以及两者之间的优缺点,最后浅浅的实现了一下!

以上便是本文的全部内容了,感谢大家的支持!!

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

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

相关文章

中兴新支点国产系统将联合阿里龙蜥社区制定多项行业标准

近日&#xff0c;从中兴新支点操作系统官方了解到&#xff0c;中兴迎来阿里龙蜥社区理事长马涛一行人&#xff0c;并进行了深度交流。会上中兴新支点操作系统回顾了近一年在龙蜥社区的贡献和投入&#xff0c;并对双方未来的合作诉求和合作计划展开了讨论。会后&#xff0c;龙蜥…

代理IP的稳定性至关重要!真实技术案例引发深思

在当今的网络世界中&#xff0c;IP代理已经成为了我们保护个人隐私、开展各类互联网业务的重要工具。不过很多人在使用IP代理时&#xff0c;常常会忽视一个关键因素——代理IP的稳定性。今天我们就来谈谈这个问题&#xff0c;并分享一个真实的案例&#xff0c;希望能引起大家对…

linux粘滞位的介绍及使用

文章目录 1.粘滞位的引入2.粘滞位的使用 1.粘滞位的引入 首先看一个场景 已知 对目录无w权限时 无法进行目录中的文件的创建/删除操作但是普通用户通过sudo命令 以root身份创建一个文件 rw- r-- r-- 普通用户此时是other 没有w权限 但却可以删除 [root和普通用户在一个目录下时…

1210. 连号区间数(枚举)

题目&#xff1a; 1210. 连号区间数 - AcWing题库 思路&#xff1a;枚举 枚举一般是先暴力再优化。 注意&#xff1a;对于区间的枚举&#xff0c;一般是定一移一。固定任何一端移动另外一端均可以。但是此题为便于在枚举移动端的过程中确定最大最小&#xff0c;选择定左移右…

TinyMce富文本编辑器使用【详细】

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&#xff1a; 开源可商用&#xff0c;基于LGPL2.1插件丰富&#xff0c;自带插件基本涵盖日常…

css3文字环绕旋转

目录 固定数量文字环绕旋转不固定数量文字环绕旋转效果图 固定数量文字环绕旋转 <!-- 文字旋转测试 --> <template><div class"page"><div><div v-for"(item, index) in [...Array(20).keys()]" :key"index" style&…

104.c语言中的define的两个模糊点

1. define 是按照从上到下的顺序的 #define 必须先定义&#xff0c;否则报错 2.函数体内的define的影响 2.1 从定义开始的位置起&#xff0c;之后都有效 不受函数作用域的限制 #include <stdio.h>//int a[N] {0};#define N 100int a[N] {0}; //int b[X]; void abcd(v…

高等数学教材重难点题型总结(三)函数与极限

首先是考研大纲包含的内容&#xff1a; 1.理解并会用罗尔(Rolle)定理、拉格朗日(Lagrange)中值定理和泰勒(Taylor)定理&#xff0c;了解并会用柯西(Cauchy)中值定理. 2.掌握用洛必达法则求未定式极限的方法. 3.理解函数的极值概念&#xff0c;掌握用导数判断函数的单调性和求函…

基于SSM的在线作业管理系统 -octopus-master(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

虚幻5 删除C盘缓存及修改缓存路径

一.修改C盘缓存 C盘缓存路径为&#xff1a; C:\Users\xx(这里是你的用户名)\AppData\Local\UnrealEngine\Common\DerivedDataCache 注意&#xff0c;如果没有AppData文件夹&#xff0c;请依次点击查看-勾选显示隐藏的项目&#xff0c;即可 可删除里面的所有文件即可 二.修改…

leetcode 刷题 - 有效三角形个数 - 长度最小的子数组 - 无重复字符的最长子串

l611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1:输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3示…

【Git】Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c;…

天翼云江西分公司副总经理彭越华一行莅临拓世科技集团指导考察,共绘蓝图开启智能新篇章

世界经济脉络在数字化的浪潮中迎来了新的生机&#xff0c;企业的成长轨迹正在智能化的力量下重新塑造。天翼云科技有限公司江西分公司副总经理彭越华一行的到访&#xff0c;为拓世科技集团带来了新的发展机遇。这场深入的交流&#xff0c;不仅预示着在科技创新和数字化转型的征…

【漏洞复现】BYTEVALUE智能流控路由器存在命令执行

【漏洞介绍】 百为智能流控路由器 /goform/webRead/open 路由的 ?path 参数存在有回显的命令注入漏洞。攻击者可通过该漏洞在服务器端执行命令&#xff0c;写入后门&#xff0c;获取服务器权限&#xff0c;从而获取路由器权限。 【指纹】 title”BYTEVALUE 智能流控路由器”…

Electron-vue出现GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案

GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案 使用版本解决方案解决总结 使用版本 以下是我解决此问题时使用的electron和vue等的一些版本信息 【附】经过测试 electron 的版本为 13.1.4 时也能解决 解决方案 将项目下的 .electron-vue/dev-runner.js…

Node版本管理工具——Nvm

文章目录 前言基础常识彼此之间的关系 一、安装 nvm&#xff1f;查看是否安装成功 二、配置下载源三、nvm常用命令 前言 nvm 全名 node.js version management&#xff0c;顾名思义是一个nodejs的版本管理工具。通过它可以安装和切换不同版本的nodejs。 基础常识 node&#x…

Java时间工具类:ZTDateTimeUtil

目录 1.返回指定格式的当前时间,Date-->FormatString,Date类型转Strig 2.返回固定格式的Date类型时间Date---》ToString---》ToDate,Date类型格式化成Date 3.字符串转日期 String格式化成String 4.两时间关系判断构件 5.Date转换为字符串:Date格式化成String 6.String类…

【canvas】在Vue3+ts中实现 canva内的矩形拖动操作。

前言 canvas内的显示内容如何拖动&#xff1f; 这里提供一个 canvas内矩形移动的解决思路。 描述 如何选中canvas里的某部分矩形内容&#xff0c;然后进行拖动&#xff1f; 我的解决思路&#xff1a; **画布搭建。**用一个div将canvas元素包裹&#xff0c;设置宽高&#xf…

净利暴跌9成,主力业务下滑,这家全球知名CIS供应商如何“翻身”?

消费电子寒冬对上游供应链的影响还在持续。 近日&#xff0c;全球知名的CMOS图像传感器&#xff08;CIS&#xff09;供应商格科微发布三季报显示&#xff0c;前三季度共实现营业收入32.45亿元&#xff0c;同比下降29.01%&#xff1b;实现净利润4972.57万元&#xff0c;同比下降…

国际阿里云:无法ping通ECS实例公网IP的排查方法!!!

无法ping通ECS实例的原因较多&#xff0c;您可以参考本文进行排查。 问题现象 本地客户端无法ping通目标ECS实例公网IP&#xff0c;例如&#xff1a; 本地客户端为Linux系统&#xff0c;ping目标ECS实例公网IP时无响应&#xff0c;如下所示&#xff1a; 本地客户端为Windo…