本文思维导图:
文章目录
🍉博主主页:@在肯德基吃麻辣烫
前言
tips: 关于前两篇文章所提到的sudo指令
我们知道,sudo指令后面紧跟的一条指令,该条指令是以root身份执行的对于有一些我们普通用户无法执行的指令,就需要用到该指令进行提权。
sudo + 指令
功能:以管理员身份执行该条指令
比如:
sudo touch mycode.c
然而我们执行该条指令时,却发现这样的问题:
意思是说张三这个用户不在sudoers这个文件当中。
举个例子:学校门口保安对认识的人他可以不问这个人是干什么的,直接就给放行了, 对不认识的人会询问,问完之后还是不给放行。
对一些做过坏事并且被保安记住的人,问都不问,一定不给放行。
上面三种情况分别就是生活中的白名单,普通人,黑名单
所以我们需要将zhangsan这个用户添加到Linux系统信任的白名单里面,才可以使用sudo指令提权。(必须是root用户才可以添加名单)
步骤:
1.在root用户下输入:
vim /etc/sudoers --使用vim编辑器打开etc目录下的sudoers文件,
按shift+;进入底行模式,输入set nu,配置一下,相当于给该文件标记了行号:
按Esc退出底行模式,进入命令模式输入100+shift+g,将光标移动到大概100行的位置
快速按两次yy指令复制root行的指令,再按p粘贴,随后进入插入模式,将张三的用户名字添加进去即可。
shift+;进入命令模式,wq!保存并强制退出即可。
此时zhangsan用户成功被添加到系统所信任的白名单中。
再次以zhangsan的身份执行
sudo touch code1.c
即可提权到root下执行touch code1.c指令
一、gcc/g++编译器的认识和使用
tips
为什么我们可以在Windows或者Linux上编译C/C++代码呢?
实际上,我们有Visual Studio 编译器还不行,还需要有各种头文件和库文件来共同支撑配合才能够实现编译C/C++的代码。
所以我们在安装编译器的时候,顺带已经安装了各种头文件和库文件。
一个.c文件会经过预编译(预处理),编译,汇编,链接等主要步骤最终才会生成可执行程序。
下面来逐一讲解:
1.预处理
预处理阶段会做一下几个工作:
去掉注释
头文件展开
条件编译
宏替换
指令:
gcc -E code.c -o code.i
将code.c文件经过预编译器进行预处理后,得到一个干净的文件。
- -E:预编译指令,后面紧跟的是待预编译文件
- -o:生成的目标文件指令前缀,后面紧跟的是生成的目标文件的名字
比如:
样例代码:
1 #include<stdio.h>
2 #define M 100
3 int main()
4 {
5 #ifdef DEBUG
6
7 printf("Hello Linux:aaa,%d\n",M);
8 #else
9 printf("Hello Linux\n");
10 #endif
11 //printf("Hello Linux\n");
12 //printf("Hello Linux\n");
13 //printf("Hello Linux\n");
14 //printf("Hello Linux\n");
15 //printf("Hello Linux\n");
16 //printf("Hello Linux\n");
17 //printf("Hello Linux\n");
18 //printf("Hello Linux\n");
19 printf("Hello Linux:bbb\n");
20 printf("Hello Linux:ccc\n");
21 return 0;
22 }
在经过预编译阶段后,形成的code.i文件如下:
对比发现,code.i文件有800多行代码,这是因为头文件的内容被拷贝到code.c文件去了。
在code.c文件所注释的内容也同样被去掉了,定义的宏最终被替换掉。
经过条件编译后,只留下一条语句。
这个过程就是code.c文件经过预编译所发生的动作。
2. 编译
编译阶段是将预编译生成的code.i文件经过编译器生成code.s文件
指令:
gcc -S code.i -o code.s
- -S:编译指令,后面紧跟的是待编译文件
- -o:生成的目标文件指令前缀,后面紧跟的是生成的目标文件的名字
- .s后缀:编译完成后生成的汇编语言
打开code.s文件,内容是这样的:
这个过程是编译器将code.i文件编译后生成的汇编文件code.s
3.汇编
汇编过程是将汇编文件code.s翻译成二进制机器码给机器进行识别。
指令:
gcc -c code.s -o code.o
- -c:汇编指令,后面紧跟的是待汇编操作文件
- -o:生成的目标文件指令前缀,后面紧跟的是生成的目标文件的名字
- .o后缀:编译完成后生成的二进制机器码,叫做可重定位二进制目标文件
打开二进制机器码,我们是看不懂的,因为vim是文本编辑器,只认识文本,不认识二进制。
不过我们还可以用一条指令以二进制的方式打开:
od code.o
- od:以二进制的方式打开code.o文件
注意:.o文件是不能独立执行的。
需要经过链接才能执行。
4.链接
链接过程是将汇编生成的.o文件经过和动态库/静态库的连接后,生成的可执行程序,这个过程就是链接。
指令:
gcc code.o -o code
- -o:生成的目标文件指令前缀,后面紧跟的是生成的目标文件的名字,这里是将可执行程序命名为code,如果不命名,默认生成 a.out可执行程序
- .o后缀:编译完成后生成的二进制机器码,叫做可重定位二进制目标文件
关于预编译,编译,汇编阶段的指令记忆方法
指令记忆方法:可以看键盘左上角的Esc按键,对应的Linux指令是:ESc
文件后缀记忆方法:参考国际标准化组织(iso
)或者镜像文件后缀(.iso
),与指令一一对应来记忆。
总结:
上面的内容讲述了一个.c文件经过gcc编译器分别进行预编译,编译,汇编,链接等主要步骤后,生成可执行程序/文件的过程。
注意:上述过程可以一步一步往下走,也可以从头开始直接走到对应的过程。
比如:汇编阶段,可以用编译阶段生成的.s文件来作为待汇编文件,也可以直接使用最原始的.c文件直接经过预编译,编译,汇编的过程
二、gcc/g++指令汇总
- -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输-出文件里面
- -S 编译到汇编语言不进行汇编和链接
- -c 编译到目标代码
- -o 文件输出到 文件
- -static 此选项对生成的文件采用静态链接
- -g 生成调试信息。GNU 调试器可利用该信息。
- -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
- -O0,-O1, -O2,-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
- -w 不生成任何警告信息。
- -Wall 生成所有警告信息。
三、认识动静态库
1.库的认知
库其实是由许许多多源文件经过一定的编译,打包后形成的。
只需要提供一个.c库文件,不需要再提供许多其他的源文件,库的存在提高了代码使用的便利性,使用别人打包好的库,可以帮助我们事半功倍地提高工作效率。同样c++的库也是由许多.cpp源文件经过一定的编译打包后形成库,只对外开放一个库文件即可。
这样也解释了gcc编译器会自动去寻找.c的库,g++编译器会去寻找.cpp的库,gcc编译器默认并不认识.cpp的库,所以让gcc编译c++的代码是行不通的。
库的命名规则
在Linux中,动态库的命名规则一般是:
libname.so.XXX/libname.so——动态库
libname.a——静态库
其中:
lib是前缀,.so.XXX/.so是后缀
真正的动态库名字只有name那一部分
对于静态也是如此
比如:
这个就是c的动态库。
静态库如上。
静态库安装方法
sudo yun install -y glibc-static
2.什么是动静态库
对于动态库(也叫共享库):动态库就像是一个网吧,可执行程序就像是网民,网名想要上网必须去到网吧,可执行程序想要运行,就必须去到动态库中将动态库的地址拷贝到本地,通过地址获取内容,达到链接的目的。
对于静态库:静态哭就像是一台电脑,可执行程序就像是网民,网名直接将电脑买回家中,就相当于可执行程序直接将静态库的内容直接拷贝到本地,达到链接的目的。
3.动静态库优缺点
动态库优缺点:
优点:可执行程序只是拷贝动态库的地址,通过地址获取内容,大大减少了内存消耗,节省资源(磁盘空间,内存空间,网络空间)
缺点:一旦动态库缺失,所有使用动态库的可执行程序将无法运行。
静态库优缺点:
优点:静态库是否缺失与可执行程序无关,即使静态库缺失,可执行程序仍然可以运行。
缺点:可执行程序将静态库的内容直接拷贝到本地,大大增加了资源消耗(磁盘空间,内存空间,网络空间)。
系统默认优先使用动态库。
4.链接方式
- 动态链接
- 静态连接
动态库只能使用动态链接,静态库只能使用静态链接。
动态链接:
gcc code.c -o code
静态链接:
gcc code.c -o code_static -static
1.链接成功后,使用下面的指令查看是否使用动态库:
ldd code
2.还可以使用下面指令查看:
file code
file code_static
从第二点所讲到,静态链接的可执行程序是要比动态链接的可执行程序要大的。
实际情况
在实际中,一般也会用到-L ,-l(L的小写),-I(i的大写)等指令共同进行动态库的连接。
比如:在c++中连接MySQL数据库。
g++ -o test test.cc -std=c++11 -I /usr/include/mysql/ -L /lib64/mysql/ -l mysqlclient
- 第一个-I(i的大写)是去指定路径下找到所需要的头文件。
- 第二个-L,是去指定路径下找到所需要的动态库(动态库一般是libXXX.so)
- 第三个-l(L的小写)是去指定路径下找到动态库的名字(以libname.so为例,去掉lib和so,中间剩下的name,就是动态库的名字)
总结:
- 1.如果没有静态库,但是仍然要-stataic,行不通。
- 2.如果有动态库和静态库,默认优先动态库,但是如果加了-staitc,那就先使用静态库,-static的本质是改变优先级,并且只能使用静态链接方案。
- 3.动态链接和静态链接不一定是纯的,可能是动态链接静态链接混合。
总结
1.实际上,我们可以直接使用gcc code.c
一步到位生成可执行程序,不过多了解具体做什么还是更有优势的。
2.对于动静态库,现在只需要掌握认识动静态库和动态链接静态链接以及它们的优缺点即可。
3.对于g++编译器,其指令和过程与gcc是几乎一样的。