目录
[二、编译器 gcc/g++](#二、编译器 gcc/g++)
一、编辑器vim:
1、对vim初步理解:
vim是一个文本编辑器, 在我们做开发的时候,主要解决我们编写代码的问题,本质上就是一个多
模式的文本编辑器
对于一门语言可以用任何一个文字编辑软件编辑,代码编辑软件多了很多功能,本质上代码都是一
个不同格式的纯文本
编辑器上只能做记录,最好的举例就是跟Windows下记事本一样,还要经过其他的处理才能称为可执行程序。
2、vim的模式:
在初步学习的过程中,首先了解3中模式即可:
a、命令模式:
首先进入vim的默认模式就是命令模式,用户所有的输入都会被当做命令
在这个模式下可以进行许多指令的操作,这个模式是一输入指令为主的,指令在下面介绍,
b、插入模式:
这就是编写代码的模式
c、底行模式:
底行模式比较特殊, vim左下方如果有:就说明现在处于底行模式,底行模式中也有很多指令,但一般常用的就是w(保存代码)q(退出vim文本编辑)
如下就是三种模式之间的转化,插入模式到底行模式之间是不能够相互转换的。
插入模式和命令模式之间的转化:
1、通过 Ins 键切换
2、通过 i 切换,切换后光标停留在原位
3、通过 a 切换,切换后光标会回退一格
4、通过 o 切换,切换后会新起一行
5、通过 s 切换 ,切换后会将光标的位置删除
3、进入与退出:
首先,在使用vim的时候要先创建一个文件,
语法:vim 文件名
注意:
如果在vim后面跟上的是不存在的文件名,那么依然会进入vim编辑模式,这个时候会先自动创建新的这个不存在的文件名,在进入vim编辑模式
输入好再按下回车之后就会跳转到如下的页面,在默认通过vim进入文本的时候是命令模式
退出的时候就先进入底行模式,然后在输入wq按下回车键即可。
4、vim命令模式下的指令集:
移动光标:
h ----- 光标向左移动一位
j ----- 光标向下移动一行
k ----- 光标向上移动一行
l ----- 光标向右移动一位
shift + ^ (输入^)----- 光标移动到当前行的行首
**shift + ** (输入)----- 光标移动到当前行的行尾
gg ----- 光标移动到当前文本的最开始
shift + g (输入G) ----- 光标移动到当前文本的最末尾
n + shift + g (输入nG) ----- 这个n是一个数字,将光标移动到第n行的开头
直接按回车 Enter----- 光标向下移动一行
n + Enter ------ 光标向下移动n行
w----- 光标从左到右,从上到下 跳到下一个单词的开头
e----- 光标从左到右,从上到下 跳到下一个单词的结尾
b----- 光标从右到左,从下到上 跳到上一个单词的开头
删除:
x -------- 删除光标所在位置的字符
nx ------ 删除光标所在位置开始往后的n个字符
X ------- 删除光标所在位置的前一个字符
nX ----- 删除光标所在位置的前n个字符
dd ------ 删除光标所在行
ndd ----- 删除光标所在行开始往下的n行
cv:
yy ----- 复制光标所在行到缓冲区
nyy ----- 复制光标所在行开始往下的n行到缓冲区
yw ----- 光标所在位置到单词尾的所有字符复制到缓冲区
nyw ----- 光标所在位置开始往后的n个字复制到缓冲区(如果当前行的单词不够就向下找)
p ------- 将已复制的内容在光标的下一行粘贴上
np ----- 将已复制的内容在光标的下一行粘贴n次
撤销:
u ------ 对应着Windows的 Ctrl + Z 撤销
Ctrl + r ------ 返回上次撤销之前的代码
其他:
shift + ` (就是输入~) ------ 将光标所在的位置进行大小写的转换
n ~ ------ 将光标及所在位置向后的n个字符进行大小写转换
r + 一个字符 ------ 将光标所在的位置替换为输入的字符
n + r + 一个字符 ------ 将光标所在的位置及后面n个字符替换为输入的字符
5、vim底行模式:
保存并退出
w ----- 保存当前的代码
q ----- 退出vim模式
两个一起按就是保存并退出
注意:
如发现wq + Enter 退不回去,就可以在最后面加上!来达到强制退出
分屏操作:
首先在底行模式下可以输指令 ------ vs 文件名 来进行多个文件的打开
以下是输入了:vs test2.cpp
如果是不存在的文件,就会在原目录下新建一个文件,然后在打开
Ctrl + ww ------ 切换屏幕的光标指令,将光标在展开的窗口中进行切换
注意:
此时光标的位置在哪一个文件的位置,此时退出的时候就是退出的哪一个文件。
二、编译器 gcc/g++
1、作用:
编译器是将我们所写的代码转化成计算机能够"看得懂"的二进制代码的过程,gcc和g++的用法几乎是一模一样的,区别就是gcc是编译C语言的g++是编译C++的(也可以编译C语言),下面以g++为例:
g++在执行编译的时候有四步:
1.预处理(去注释,头文件展开,条件编译,宏替换)
2.编译(生成汇编)
3.汇编(生成机器可识别代码,就是二进制代码)
4.链接(将汇编过程产生的二进制代码进行链接,生成可执行文件或者库文件)
2、用法:
用法: g++ 选项 文件名
选项:
1、-o ----- 将处理结果输出到指定文件,该选项后需紧跟输出的文件名
2、-E ----- 这就是只进行预处理的阶段,告诉g++,从现在开始进行程序的翻译,将预处理工作做完就停下来,不要往后走了。
3、-S ----- 从现在开始进行程序的翻译将编译工作做完就停下来
4、 -c ----- 从现在开始进行程序的翻译,将汇编工作做完就停下来
5、-static ----- 此选项对生成的文件采用静态链接
6、-g ------ 生成调试信息 成为以dubug形式,默认是release模式
预处理:
四步: 去注释,头文件展开,条件编译,宏替换
去注释:发现预处理之后的代码的注释不在了
头文件展开:发现预处理之后的代码非常长,这就是将#include<iostream> 进行展开了
条件编译:只会留下条件编译通过的语句
宏替换:发现将DATA这个被替换为100
编译:
将编译之后的代码输出到test1.s中,可以看到经过编译之后,就会生成汇编代码
汇编:
将test1.s的汇编代码转换为计算机看得懂的二进制代码:
如下是用vim打开的,这是一个乱码,毕竟使用编辑器打开的二进制
但是也可以用指令看二进制(如下是截取的部分)
bash
readelf -a test1.o
链接:
在成功编译之后,就进入了链接阶段,
若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out
将程序运行所需的各种函数链接起来,包括与库函数 的链接,Linux中一般是动态链接,链接后生成可执行文件,就可以执行了
注意:在链接后生成的可执行程序文件也是二进制的
3、函数库:
函数库分为静态库与动态库:
gcc 在编译时默认使用动态库。完成了链接之后,就可以生成可执行文件
动态库:
动态库,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为 .so
在Linux 中默认使用动态链接的方式,
可以用ldd指令来看程序所依赖的库,用法:ldd 可执行程序文件名
如上,基本可以看到动态库的标志是 libXXX.so
其中,去掉前缀lib,后缀.so,这样剩下的部分就是所调的动态库,
如上libc.so.6,去掉前缀与后缀,最后剩下的是c,就是调用C语言共享库
静态库:
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为 .a
如上所示:
test.out 就是和动态库的链接 test_static.out 就是和静态库的链接
和动态库差不多,静态库的标志是 libXXX.a
其中,去掉前缀lib,后缀.a,这样剩下的部分就是所加入的静态库,因为静态链接就是将静态库拷贝到程序中的,因此最终的程序会比动态库要大
注意:
1、如果我们没有静态库,但是我们就要在编译的时候 -static,是不可以的
2、如果我们没有动态库,只有静态库,而且g++能够找到,那能不能在编译的时候 -static,
所以,-static的本质就是改变编译链接和函数库的优先级
3、一个程序不一定只有静态库或者是动态库,有的是混合的,二者都有
比较:
静态库(.a)
优点:
- 独立性:生成的可执行文件不依赖于外部的库文件,能够在没有该库的环境中运行。
- 运行效率:由于不需要在运行时加载库,程序的启动时间较短。
- 稳定性:适用于不需要频繁更新库的场景,对于嵌入式系统或需要快速启动的应用,静态库也是一个不错的选择。
缺点:
- 文件体积:可执行文件体积较大,因为它包含了所有的库代码。
- 更新复杂:如果库更新,所有依赖于该库的可执行文件都需要重新编译。
- 资源消耗:相同的库文件可能在内存中被加载多份,消耗系统资源,浪费内存。
动态库(.so)
优点:
- 文件体积小:可执行文件相对较小,因为不包含库的所有代码。
- 易于更新:只需替换动态库文件即可更新,而不需要重新编译依赖该库的所有程序。
- 资源共享:动态库可以被多个程序共享使用,减少内存消耗。
- 灵活性:可以控制何时加载动态库,不调用库函数动态库不会被加载。
缺点:
- 运行时依赖:如果缺少所需的动态库,程序无法运行。
- 加载时间:在启动时需要加载库,可能会稍微增加启动时间。
- 可移植性问题:程序的可移植性受到影响,如果想在不同的系统上使用动态库,可能需要用到专门的库兼容器。
总结来说,静态库提供了独立性和高性能,但代价是较大的文件体积和更新困难。动态库则更适合需要共享资源或频繁更新的项目,但依赖外部库文件。在实际开发中,了解这两者的特点,并根据项目的需求做出合适的选择,将有助于编写出更加高效和维护成本更低的代码。