【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)

作者:小树苗渴望变成参天大树
❤️‍作者宣言:认真写好每一篇博客
作者gitee:gitee
作者专栏:C语言,数据结构初阶,Linux,C++
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第1张图片

如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、解决sudo无法提权的问题
  • 二、gcc/g++的作用
    • 2.1预处理
    • 2.2编译(生成汇编)
    • 2.3汇编(生成机器可识别代码)
    • 2.4链接
    • 2.5gcc选项记忆
  • 三、程序运行的原理
    • 3.1头文件的作用
    • 3.2**库文件是什么?作用是什么**
    • 3.3 动态库和静态库
  • 四、总结


前言

今天我们重点介绍一下Linux中的gcc和g++的使用,g++的使用和gcc几乎一样,所以也就是具体介绍gcc的使用,这篇文章前半部分我在C语言的程序的编译环境那篇博客也介绍过,但是是在vscode下进行演示的,当时知识在vscode上配置了gcc编译器,今天在Linux上来继续给大家回顾一下,并且可以更好的连接到后面要讲的知识。(来解决之前无法sudo的办法)


一、解决sudo无法提权的问题

在之前我们讲到权限的时候,我们如果想下载什么东西的时候,或者必须在root权限的时候去进行操作的时候,要不su切换到root权限,要不就su - 切到root用户下进行操作,但是这时候往往都只是一条指令的需要使用root权限,那我们这样来回切换显然就很麻烦,之前也提到过使用 sudo来进行提权,但是我们没有将此用户加入到系统的白名单里面,如果可以直接使用,那每条指令都加一个sudo那岂不是和root权限没啥区别了吗??所以我们需要在系统中将用户添加到白名单中。

我们先切换到我们的root权限:

vim /etc/sudoers

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第2张图片

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第3张图片

大约在这个文件的第100行,复制一份,然后再修改成普通用户名就可以了,时候 :wq! 保存强制退出,此时你在退回到你的普通账户下,就可以进行sudo提权,但是sudo提权并不是万能,Linux为了安全起见,sudo有的指令就没法进行提权,但是大部分还是可以的,希望大家下来可以配置一下

补充说明:
再没有进行sudo配置的时候,你sudo也会有提示叫你输入普通用户的密码,但是不管用,但是你sudo配置之后,也会提示你输入密码的。这时候才会有作用

二、gcc/g++的作用

  1. 预处理(进行宏替换)
  2. 编译(生成汇编)
  3. 汇编(生成机器可识别代码)
  4. 连接(生成可执行文件或库文件)

2.1预处理

预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
预处理指令是以#号开头的代码行。
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序

gcc -E test.c -o test.i

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第4张图片

我们预编译只是进行简单的展开替换,并不会生成其他文件,所以我们需要使用 -o后面是文件,一般我们习惯弄成.i文件。

条件编译的作用(简单介绍)
大家都知道我们好多开发软件都有两个版本,一个是社区版(免费的),一个是专业版(收费的),专业版的功能都会比社区版的功能要强大,但是这两个版本都是同一家公司开发并且需要维护的,如果有一天两个版本的相同功能升级之后,难道我要修改两份代码吗?增删查改都需要进行两次,那这样是不是太麻烦了,是人修改就会出现错误,所以这是我们就需要使用条件编译,维护一份代码就行了,再社区版中,我只需要使用条件编译把相应的功能给放出来运行一下,就好比上面,我只需要打印debug的信息,这预处理阶段就是完成条件编译的工作,相信讲到这里大家应该对条件编译有了一定的了解,并且也明白了预处理阶段要完成哪些事情了吧

接下来做一个铺垫:
博主随便截取一段展开的头文件当中的内容:

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第5张图片
大家看到这里都是函数的声明,并没有看到函数的定义,那函数的定义又在哪里呢,等着我们下面讲解库的时候再具体介绍,这里毕竟还是铺垫。

注意:使用-E是告诉gcc编译器进行程序的翻译工作,完成预处理阶段的工作就停下来,不要往后面走了

2.2编译(生成汇编)

在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

gcc -S test.i

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第6张图片

这个是再预编译的基础上对生成的test.i文件进行编译会默认生成.s的文件,如果你不想要这个名字可以使用-o。

注意:将程序的编译工作完成,后面就不要执行了

2.3汇编(生成机器可识别代码)

汇编阶段是把编译阶段生成的“.s”文件转成目标文件读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了

gcc -c test.s -o test.o

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第7张图片
此时test.o里面都是二进制指令,我们使用查看二进制文件的指令来看看:od test.o
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第8张图片
注意:将汇编工作做完,就不往后面走了,目前虽然生成了二进制文件,但是还需要进行链接才可以运行

2.4链接

找到对应的库文件进行连接才可以运行,我们刚才生成的test.o是没有办法直接运行的:即使我们修改了权限
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第9张图片

文件虽然具备了可执行的权限,但是没有可执行能力也是不行的,这两种是不同的概念

gcc test.o -o test

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第10张图片
但是我想讲的链接可远远不止这些,下面所介绍的也正式我们gcc的作用到底是什么,那我们开始下面知识点的介绍

2.5gcc选项记忆

esc,iso

三、程序运行的原理

3.1头文件的作用

大家有没有想过,我们为什么可以再Windows,Linux或者其他软件上进行开发呢??难道就凭我们自己写的那些代码就可以执行我们的程序了吗??相信大家再学习C语言的时候,老师就告诉我们要包含头文件,为什么要包含呢,肯定是里面有我们想要的东西,没错,头文件就是各种常用函数的声明,我们包含了这些,就可以使用里面的函数,不需要我们自己再去写一个输入输出或者其他函数,所以再我们系统中肯定装有对应的头文件

再Linux下:

ls /usr/include

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第11张图片
再Windows下:
我们下载对应的开发软件的时候都会下载对应的头文件安装包,使用everything软件去查找
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第12张图片

所以c/c++的开发环境不止vs gcc g++,还有语言本身的头文件,如果没有这些,那我们就需要自己写一些函数的定义,这些文件是创造者给我们写好的,帮助我们解决了大量的重复工作,是我们开发更加的高效

所以gcc和g++是根据不同的语言帮助我们选择到语言本身对应的头文件上的,我们来看看测试
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第13张图片

因为我们的C++是兼容C的,所以C中有的头文件C++也有,所以g++编译的时候选择的头文件也符合C语言,但是使用gcc编译c++代码的时候,就会出现错误,因为gcc选择的是C语言自身的头文件,c++写的代码有的不包含在里面就会报错

所以头文件的作用就是帮助编译器通过声明来找到函数的定义

解决疑惑:我们包含头文件为什么只包含后面的.h,为什么前面的指定路径不带上,例如#include,原因是在Linux下,这些头文件有固定的地方,所以不需要加,gcc也可以找到,在Windows下,下载对应的编译器的时候,也下载对应的头文件,编译器知道安装在那个目录下面的,所以也可以找到,所以不需要指定路径也可以。

3.2库文件是什么?作用是什么

我们上面讲到头文件,头文件里面是函数的声明,那定义在哪里呢??我们前面也做过铺垫,函数的定义就在库文件里面,库文件头文件本质都是文件,头文件就是把许多.c的源文件进行翻译,打包放到头文件里面里面的,给你提供一个头文件就可以了,其余的事情交给编译器去完成,所以这也是上面我们说过生成.o文件后还需要进行链接的原因 ,接下来我们具体来看看什么是库文件

Linux:
动态库文件(.so) 静态库文件(.a)
在这里插入图片描述
在你们的机器上应该是没有.a这个文件的,只会默认安装动态库,因为我的机器上安装过静态库,后面会教大家怎么安装

windows:
动态库文件(.dll) 静态库文件(.lib)
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第14张图片

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第15张图片
大家目前知道有这两种库了,他的作用就是给链接时提供函数的定义
有了这两种库我们就可以进行链接,这些文件打开可能是看不懂的代码,大家知道里面是函数的实现的就行

总结:头文件的声明·的函数+库文件定义的函数+自己写的代码=可执行程序

3.3 动态库和静态库

上面介绍到我们有这两种库,但是他们到底时什么呢,接下来具体介绍一下。我用一个生动形象的故事带大家理解这两个库的概念:
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第16张图片

  1. 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
  2. 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,

解释: 我们上面图中描述的是,静态库是买二手电脑,自然而然宿舍体积变大了,动态库就不会出现这样,所以动态库比静态库更节省系统消耗

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第17张图片

注意:动态库一旦缺失,程序就运行不起来了,不止一个程序,静态库是将自己的函数实现拷贝到你的程序中,后面不在依赖静态库,你的同学就是系统的指令,所以这里没办法给大家展示没有动态库会出现什么情况。


系统默认是有动态库的,接下来教大家下载静态库:

sudo yum install -y glibc-static//c
sudo yum install -y libstdc++-static//c++

接下来我们来验证我们在链接的时候到底是链接那个库:

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第18张图片
上面我们经过预处理,编译,汇编,接下来进行连接
动态链接:默认链接就是动态的

ldd 查看可执行程序链接哪个库

【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第19张图片
静态链接:加一个-static
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第20张图片
通过验证我们是发现了可执行程序链接不同的库,而且链接静态库的体积明显大很多。

或者使用file指令去查看也行
在这里插入图片描述

解决疑惑:

  1. 没有静态库,但是我们就要使用-static行不行? 答案是不行的
  2. 没有动态库,只使用静态库,并且可以找到,可以只-static吗??答案是可以的,-static的本质就是,改变链接优先级,本来是先匹配动态库,再匹配静态库,加-static只会匹配静态库
  3. 默认的一定链接的就是动态库吗??答案是不对的,默认的匹配时混合的,不一定是纯的动态库。

动态库和静态库的优缺点:
动态库优点:动态库也是共享库,可以有效节省资源
缺点:一旦缺失,导致好多程序不能运行

静态库优点:不依赖库,程序可以独立运行
缺点:体积大,消耗资源

关于动态库和静态库大家应该有了一定的了解了吧,今天我就给大家讲解概念和链接原理,后面有细节,我在细说。

四、总结

今天这篇难度不大,大家会使用gcc和g++就行了,通过今天这篇大家对两个编译器有了更深的了解,也了解我们写的代码到底是怎么变成可执行程序的,那我们今天的分享就先到这里了,我们下篇再见。
【Linux】-编译器-gcc/g++使用以及动态库和静态库的介绍(以及解决sudo失败的方法)_第21张图片

你可能感兴趣的:(Linux,linux)