📃博客主页: 小镇敲码人
💚代码仓库,欢迎访问
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞
【Linux学习工具篇】之vim和gcc
- vim
- vim的安装
- vim的三种模式
- 正常模式
- 底行模式
- 插入模式
- vim的配置
- 给普通用户添加sudo
- Linux编译器gcc与g++
- gcc完成翻译的过程
- 编译器和语言的自举过程
- 预处理阶段
- 编译阶段
- 汇编阶段
- 链接阶段
- 对动静态库的理解
- 动态库
- 静态库
- 动静态库的比较
- 常见的三种目标文件
- include文件和库文件
- 动态链接和静态链接
前言:上篇博客我们介绍了
apt
镜像源文件的配置以及apt
的使用,今天这篇博客让我们来学习Linux上的编辑器vim
和编译器gcc
/g++。
vim
vim
是一种Linux上常见的多模式编辑器。它是vi
的升级版,兼容所有vi
的操作。增加了一些新特性,如代码补全、编译及错误跳转
vim的安装
使用apt install -y vim
可以直接在Linux下安装vim
,但是注意需要root
权限或者sudo
。
vim的三种模式
vim
不仅仅只有三种模式,它一共有12种模式。这里我们只介绍三种:正常模式(又叫命令模式)、底行模式、插入模式。
正常模式
正常模式也叫做命令模式。用于导航、编辑、复制和粘贴文本,以及执行各种命令。在正常模式下,按键被解释为命令,而不是直接插入文本。
一般我们使用vim [文件名]
就会进入vim
的页面,默认就是正常模式。
还可以vim [文件名] +行号
默认打开就光标就会跳到该行。否则光标就会在上次退出的时候的位置。
正常模式下的命令集:
Shift + $:光标定位到当前行的最右侧结尾处。
Shift + ^:光标定位到当前行的最左侧结尾处。
Shift + g:光标定位到文本的最后一行最左侧结尾处。
n + Shift + g:光标定位到第n行开始处,注意n不要长按,比如想跳转到第二行开始处,按一个2,再按Shift+g就会跳转到第二行开始处了。
gg:光标定位到文本的最开始。
h/j/k/l:分别对应光标左移、下移、上移、右移。快速记忆小技巧:h在最左边->左移,l在最右边->右移,j(jump):一般跳都是向下跳->下移,k(king):王都是高高在上的->上移。
背景知识:Vim的前身Vi是作为terminal friendly的编辑器而设计出来的,保证在Unix的文字终端上能正常工作是非常重要的性质。但早期Unix的文字终端只能传输ASCII 127以内的字符,不包括需要用控制键的上下左右(那个时候的键盘还没有标准的上下左右键)。因此,设计师选择了HJKL这四个字母键作为移动键,以适应当时的硬件限制。
w:按照`单词`在行内进行移动(后)。
b:按照`单词`在行内进行移动(前)。
Shift + ww:多界面切换。
Shift + zz = ZZ:保存并退出vim。
n+yy:复制当前行/多行。
n+p:在下一行进行粘贴/多行。
u:撤销上一次的操作。
ctrl+r:对上一次的撤销进行撤销。
n+dd:删除(剪切)当前行(多行)。
Shift+` = ~:当前光标所指的字符(如果是英文字符)进行大小写快速切换。
n+r:替换当前光标所在字符为n,注意要同时按。
Shift+r = R:替换模式。进入替换模式,可任意将光标所在字符替换为你想替换的字符。
n+x:删除从当前光标起的n个字符(右侧)。先按要删除的字符数,再按x。
n+Shift+x:删除从当前光标起的n个字符(左侧)。先输入要删除的字符数,再输入X(Shift+x)。
Shift+3 = #:高亮要查找的函数名或者变量名。输入n跳到下一查找到的函数名。
正常模式下批量化注释:
-
ctrl v。进入可视块模式。可视块模式允许用户选择矩形区域内的文本,然后对这个选定的文本块进行复制、删除、替换等操作。
-
hjkl进行区域选择。
-
Shift+i=I进入插入模式,并输入
//
。 -
最后按键盘左上角
Esc
键退出插入模式。就批量化注释完成。
正常模式下批量化去注释:
-
ctrl v
进入可视块模式。 -
hjkl
选择区域。 -
d
删除选择区域的内容。
正常模式转插入模式:Shift + i/o/a
等价于I/O/A
,模式切换成功vim
下面会出现插入/Insert
的字样。
正常模式转底行模式:Shift + ;
等价于:
。当页面最低部出现:
代表已经切换为底行模式。
底行模式
通过冒号(:)进入,用于执行各种高级命令,如保存文件、退出编辑器、全局替换文本等。
底行模式常见的命令集:
w:保存。
q:退出,不保存更改。
wq:保存并退出
wq!:强制保存并退出。(! 通常用于覆盖某些安全性或确认提示。)
w!:强制保存。
q!:强制退出。
vs filename:vim支持同时打开文件,光标在哪哪个界面我们就正在编辑哪个界面。
正常模式下:ctrl+ww:光标多界面切换。
set nu:显示文件的行号。
n:在冒号后输入一个数字,光标会自动跳转到该行。
/要搜索的字符:如果没有搜索到满意的字符,可以输入n跳转到下一查找的字符,/是从前往后查找。
?要搜索的字符:?与/唯一的区别是?是从后往前查找。
- 底行模式要退出进入命令模式,直接按键盘左上角的
Esc
即可。底行模式不可直接进入插入模式。
插入模式
用于输入文本,类似于普通文本编辑器的行为。在正常模式下,可以通过特定的命令切换到插入模式。
插入模式也不能直接切换到底行模式,它可以切换到正常模式,和底行模式一样,插入模式下按Esc
键即可。
Shift+Insert
:可以帮助我们在插入模式下粘贴内容。这种太复杂,我们后续会介绍在配置文件中配置,让vim
支持鼠标右键复制粘贴。
但是原生的vim
使用起来很不方便,没有语法高亮和代码补全,这些我们都可以自己去配置文件里面配置。
vim的配置
-
首先打开文件
/etc/vim/vimrc
,这个是系统中公共的配置文件,修改它会对所有的用户生效。除了这个文件在每个用户的家目录下还有文件
.vimrc
,在这个文件里面配置只对该用户生效。如果没有可以自己创建。 -
常见的配置项。建议配置到文件
~/.vimrc
中。参考博客syntax on " Set syntax highlighting set number " Set the line number set tabstop=4 " Set an indent to account for 4 spaces set autoindent " Set up automatic indentation set mouse=a " Set mouse is always available, set mouse= (empty) cancel set cc=80 " Column 80 highlighted, set cc=0 cancellation set cursorline " Settings to highlight the current row set cindent " Format C language set st=4 " Set the width of the soft tab to 4 spaces set shiftwidth=4 " The width automatically indented when setting a new line is 4 spaces set sts=4 " Set the number of spaces inserted when the Tab key is pressed in insertion mode to 4 set ruler " Show the status of the last line set showmode " The status of this row is displayed in the lower left corner. set bg=dark " Show different background tones set hlsearch " Enable Search Highlight set laststatus=2 " Always display the status bar set backspace=2 set mouse=v
-
介绍一下最后一个
set backspace=2
,backspace
的模式有三种,只有设成2我们才能在插入模式下任意使用删除键,否则默认有些情况是不能使用删除键的,即使你在插入模式下。 -
set mouse=v
:支持鼠标右键复制粘贴 。 -
复制粘贴即可,保存并退出配置文件即可启用。
-
效果图:
给普通用户添加sudo
sudo
是一个在Linux系统中用于执行特权命令的超级用户工具,其全称为“superuser do”的简写。以下是关于sudo
的详细解释:
sudo
允许系统管理员授权普通用户执行部分或全部root命令,而无需直接登录为root用户。这样可以减少root登录,从而提高系统的安全性。
它的授权机制依赖于
/etc/sudoers
文件。
-
一般情况下,如果没有给普通用户添加
sudo
的权限,他是无法使用sudo
的。 -
root用户下,打开文件
/etc/sudoers
。
打开后找到类似行,增加username ALL=(ALL:ALL) ALL
,username
是你要增加sudo
的用户名。保存即配置成功。
-
更改完成后,强制保存退出即可。
-
效果图。现在普通用户可以使用
sudo
了。不用
sudo
,就会报权限不够的错误:
Linux编译器gcc与g++
这两个编译器在博客C/C++程序预处理与环境已经介绍了很多,今天我们来介绍一些我们之前没有介绍的知识。
gcc完成翻译的过程
gcc完成编译分为四个阶段:预处理、编译、汇编、连接。
编译器和语言的自举过程
想弄清楚程序翻译的过程,我们需要知道编译器和语言的自举过程,是先诞生某个语言,还是先诞生用某个语言写的编译器。结论:**是先有编程语言的设计和规范,然后才有用该语言编写的编译器。**原因如下:
-
编译器的作用:首先我们都知道,编译器(
gcc
,g++
)是一种软件,它的功能是将高级语言(java
、C
/C++
)编写的代码翻译成机器语言(计算机能够理解并且执行的代码)。编译器使得程序员可以使用更高级、更易读的语言,而不需要直接处理复杂难懂的机器语言。 -
编译器与编程语言的依赖作用:从理论上分析,即使一个编程语言没有解释这种语言的编译器,这种语言的设计文档和规范可以存在,但如果没有编译器或解释器,它就不能被用于实际的编程任务。所以实际中,为了使编程语言能够被实际使用,通常需要一个编译器或解释器来执行用该语言编写的代码。
-
真实的发展过程:一种编程语言在创建之初,会先使用用其它编程语言编写的编译器来编译和解释它,我们称其为编译C语言的编译器
V1
版本。然后我们用C语言写一个编译器,用V1去
编译它形成软件V2
。后面我们有了更好的方案,又可以去在V2
源代码的基础上修改,使用V2
编译形成V3
编译器,这是语言和编译器的自举过程。下面以汇编语言和汇编语言编译器的自举过程来直观的感受一下:
预处理阶段
预处理阶段要做的事情:头文件展开、宏替换、去注释、条件编译。
预处理指令:gcc -E test.c -o test.i
。
之前没有叙述过-E
选项的作用:-E
选项是告诉编译器,从现在开始进行程序的翻译过程,预处理完成后就停下来。
预处理完成后,还是C语言。
编译阶段
-
编译阶段要做的事情:检查代码的规范性,是否有语法错误,检查无误后,将C语言翻译成汇编语言。为什么不是直接翻译成机器语言呢?**在已有的编译工具链中,汇编器是负责将汇编语言翻译成机器语言的工具。如果编译器直接将C语言翻译成机器语言,那么就需要重新设计整个编译工具链,这将大大增加开发成本和复杂度。**总之就是这样设计可以充分利用已有的资源,将汇编语言翻译成机器语言这个工作已经有前人做过,但是将C语言或者其他的高级语言直接翻译为机器语言,这个难度比先将C语言翻译为汇编语言再让汇编器将汇编语言翻译成机器语言要大的多。
-
编译指令:
gcc -S test.i -o test.s
。-E
选项的作用:从现在开始进行程序的翻译,当编译工作做完就停下来。
-
编译工作完成,我们的代码已经被翻译为汇编语言了。
汇编阶段
-
汇编阶段要做的事情:它的主要工作是将汇编语言翻译为二进制语言,一些细节不再赘述。
-
指令:
gcc -c test.s -o test.o
。-c
选项的作用:从现在开始进行程序的翻译,当汇编工作做完就停下来。- 生成的
test.o
文件不是可执行文件,它通常是一个可重定向的二进制目标文件。这个文件还不能直接执行,因为它通常只包含了程序的机器指令部分,而缺少了程序的入口点、内存布局、与其他程序或库的链接信息等必要信息。
链接阶段
-
链接阶段要做的事情:生成可执行文件。
-
指令:
gcc test.o -o test
对动静态库的理解
动静态库在在不同的操作系统中,后缀不一样。在Linux操作系统中,动态库的后缀是
.so
,静态库的后缀是.a
;而在Windows操作系统中,动态库的后缀是.dll
,静态库文件的后缀是.lib
。
动态库
- 概念:动态库(也称为共享库)在程序运行时被加载。这意味着,虽然程序在编译时指定了要使用的库,但库中的代码并不会被复制到最终的可执行文件中。相反,程序会包含对库中函数的引用,并在运行时通过操作系统的加载器(如Windows的LoadLibrary或Linux的dlopen)来加载所需的库。— 动态库相当于是编译器告诉你库中函数的地址,然后可执行程序执行的时候,去调用相应的函数。
静态库
- 概念:静态库(通常以
.a
为后缀)包含了一组编译好的目标文件(.o
文件),这些目标文件中包含了程序的代码和数据。在编译阶段,链接器会将静态库中的目标文件与程序的其他部分进行链接,生成最终的可执行文件。
动静态库的比较
下面一张表格,详细介绍动静态库的优缺点:
以下是一个总结动态库(共享库)和静态库优缺点的表格:
动态库(共享库) | 静态库 | |
---|---|---|
优点 | 1. 多个程序可以共享同一个库文件,节省磁盘空间。 | 1. 程序运行时无需外部库文件,减少了运行时的依赖。 |
2. 库更新时,只需替换库文件,无需重新编译使用了该库的程序。 | 2. 避免了动态链接可能带来的性能开销(尽管现代系统已大大减少了这种差异)。 | |
3. 便于调试和版本控制,因为库文件是独立的。 | 3. 程序更加独立,不依赖于外部库文件的路径和版本。 | |
4. 增加了代码的复用性和模块化。 | ||
缺点 | 1. 程序运行时需要库文件的存在,如果库文件丢失或损坏,程序将无法运行。 | 1. 程序体积大,因为整个库都被包含在内。 |
2. 动态链接可能引入一些性能开销,尽管现代系统已对此进行了优化。 | 2. 如果库需要更新,必须重新编译所有使用了该库的程序。 | |
3. 可能存在版本兼容性问题,不同版本的程序可能需要不同版本的库。 | ||
4. 在某些情况下,动态库的加载可能会增加程序的启动时间。 |
常见的三种目标文件
-
可重定位目标文件。
这种文件就是C语言程序经过汇编生成的文件,它有如下的特点。典型的可重定位目标文件就是我们C语言程序经过汇编阶段后生成的
.o
文件。- 包含二进制代码和数据。
- 它可以和其它的可重定向目标文件在链接时期合并,以创建一个可执行文件。
- 可重定位文件中的代码和数据是相对地址,而不是绝对地址。这意味着它们的加载地址可以在链接时进行调整,以便适应最终的内存布局。
-
可执行目标文件
这种文件是C语言完成编译后生成的。也包含二进制代码和数据。
- 可执行目标文件是程序的最终形式,可以被操作系统加载并运行。
-
共享目标文件。
共享目标文件是动态库的一种,它是一种特殊的可重定位目标文件。
-
可以在加载或运行时被动态地加载进内存并链接。
-
共享目标文件通常用于实现动态链接库(
DLL
)或共享库(.so
文件),这些库可以在多个程序之间共享,以减少磁盘空间的使用并提高代码的复用性。
-
- 在Linux下使用
readelf -a filename
可以查看目标文件的ELF格式。该指令还有一些其它的选项可以用来查看不同的内容。
include文件和库文件
-
include文件
也被称为头文件,在C/C++中使用
#include
这个预处理指令被包含进来。-
在C/C++等编程语言中,头文件通常用于声明函数、宏、变量和数据类型等,而不包含实际的实现代码。头文件的主要目的是提供接口或协议,使得其他源文件可以引用这些声明并与之交互。
-
Linux中头文件,通常在路径
/usr/include
中。
-
-
库文件
库文件是一种目标文件。静态库是可重定位目标文件,动态库是共享目标文件,上面已经具体介绍过了。
-
尽管头文件提供了函数和变量的声明,但实际的实现代码仍然需要某种形式的存储和分发。这就是库文件的作用所在。头文件主要用于提供声明和接口,而库文件则用于存储和实现这些声明所对应的代码。因此,在软件开发中,我们需要同时使用头文件和库文件来满足不同的需求和目标。
-
Linux中一般
/usr/lib
、/usr/lib64
、/lib
、/lib64
都包含库文件。
-
动态链接和静态链接
-
动态链接,gcc/g++编译器默认就是动态链接。
直接一步完成编译链接的过程:
gcc -o mybin mytest
。使用
ldd 可执行文件
可以查看它依赖的库:
.so
结尾,所以默认是动态链接。
-
静态链接,需要使用选项
-static
。指令:
gcc -o mybin-static mytest.c -static
ldd mybin-static
:
- 本人知识、能力有限,若有错漏,烦请指正,非常非常感谢!!!
- 转发或者引用需标明来源。