Linux 软件包管理器 yum
在我们Linux平台下,若想去使用编译器去编辑代码,需要进行安装vim,那么如何进行安装vim呢?
首先,我们需要在命令行中进行搜索 在网络保障的环境下输入yum list | grep lrzsz
搜索结果如下
lrzsz.x86_64 0.12.20-36.el7 @base
前面的表示64位系统下的安装包,选择包是要与系统匹配,后面是版本号以及软件源,软件源我们可以理解为相当于windows下的应用商店
接下来就要开始我们的安装了
在命令行中输入 sudo yum install lrzsz
而后yum就会自动找到需要下载的软件包,我们再敲入y确认安装即可,而后会出现complete字样,说明安装完成
注意:安装软件时由于需要向系统目录中写入内容, 一般需要 sudo 或者切到 root 账户下才能完成.
yum 安装软件只能一个装完了再装另一个 . 正在 yum 安装一个软件的过程中 , 如果再尝试用 yum 安装另外一个软件, yum 会报错
那么我们如何卸载软件呢,也是仅需要一条命令
sudo yum remove lrzsz
即可完成卸载
当我们完成vim的安装之后,我们就可以来探究下其作用
我们知道,我们的vs2013是一个集成开发环境,需要满足多种应用场景
我们用上面的简单关系可以去类比Linux与vs的对应关系
vim模式切换
而我们的vim到底是什么呢?其实我们可以理解为文本编辑器,可以用来写代码的
vim特征
1.vim是一个多模式的编辑器,默认处在命令模式,所以当我们第一次打开vim时,键盘的大多数操作都是不起作用的
2.vim(命令模式,插入(编辑)模式,底行模式)
3.命令->插入: i(光标不变),a(同行的下一个位置),o(新起一行)
4.插入->命令:esc(键盘左上角)
5.进入底行:需要从命令模式进入,shift+:.vim可以从底行进行退出,w保存,q退出,wq保存+退出
总的来说可以理解为:esc负责回到命令模式,i,a,o负责切入到插入模式,shift+:负责进入底行模式,当我们需要进入底行或者插入时,都得先使用esc返回到命令模式
vim基本使用
vim命令模式:常见的命令需要在命令模式下进行操作
行操作
[yy]:复制本行
[nyy]:复制n行内容,从当前光标开始
[dd]:删除光标所在行,更像剪切+删除
[ndd]:批量删除一批连续的内容
[p]:粘贴,光标在哪里,就粘贴再下一行
[np]:n代表个数
[u]:撤销上次动作
光标定位
[gg]:将光标定位在文件的最开始
[shift+g]:将光标定位到文件的最结尾
[n,shift+g]:将光标定位到任意一行
[shift+4]($):将光标定位到当前行的最结尾,锚点
[shift+6](^):将光标定位到当前行的最开始,锚点
[b,w]:按照单词进行前移或者后移
[nb,nw]:按照n个单词进行前移或者后移
[x,nx]删除光标所在文本内容,从左->右
[shift +x]:删除光标所在文本内容从右->左
[shift+~]批量化大小写转化
[h,j,k,l]:左右上下
底行常见命令:
[/or?]:查找文本,n选择下一个
[set nu/nonu]:调出行号或取消
gcc编译器
我们在这里回顾一下我们的文件编译连接过程
翻译:预处理/编译/汇编/链接
预处理:头文件展开,去注释,宏替换,条件编译
编译:将C代码翻译形成汇编代码
汇编:将汇编形成目标二进制文件
链接:将目标文件与系统库进行链接形成可执行程序
-E(.i),-S(.s), -C(.o) ,-o(可执行程序)
预处理 ( 进行宏替换 )预处理功能主要包括宏定义 , 文件包含 , 条件编译 , 去注释等。预处理指令是以 # 号开头的代码行。实例 : gcc –E hello.c –o hello.i选项 “-E”, 该选项的作用是让 gcc 在预处理结束后停止编译过程。选项 “-o” 是指目标文件 ,“.i” 文件为已经过预处理的 C 原始程序。编译(生成汇编)在这个阶段中 ,gcc 首先要检查代码的规范性、是否有语法错误等 , 以确定代码的实际要做的工作 , 在检查无误后 ,gcc 把代码翻译成汇编语言。用户可以使用 “-S” 选项来进行查看 , 该选项只进行编译而不进行汇编 , 生成汇编代码。实例 : gcc –S hello.i –o hello.s汇编(生成机器可识别代码)汇编阶段是把编译阶段生成的 “.s” 文件转成目标文件读者在此可使用选项 “-c” 就可看到汇编代码已转化为 “.o” 的二进制目标代码了实例 : gcc –c hello.s –o hello.o连接(生成可执行文件或库文件)在成功编译之后 , 就进入了链接阶段。实例 : gcc hello.o –o hello
我们在vim中创建出hello.i文件,与hello.c文件一起打开
可以发现,其将头文件进行了展开
将注释进行了去除
我们利用之前生成的hello.i文件,继续进行编译生成hello.s文件
在hello.s中,展示的就是我们的汇编语言了
其次我们再利用hello.s创建hello.o文件(其实这些步骤也可以一步生成)
我们将hello.o文件打开,可以看到全部都是乱码,这其实是已经被翻译成二进制的文件了
我们使用od命令将这个文件以8进制打出来
我们经过上面的展开,其实我们已经可以了解到,一个文件其实是拥有4个文件的
当我们完成上面步骤进入了链接阶段,生成hello.o文件,gcc/g++不带-E,-S,-c选项时,便会默认生成预处理,编译,汇编,链接全过程后的文件,不用-o选项生成指定文件的文件名,则默认生成可执行文件名为a.out
我们的gcc编译器是有能力找到自己支持的库和头文件的
静态库与动态库
: 函数库我们的 C 程序中,并没有定义 “printf” 的函数实现 , 且在预编译中包含的 “stdio.h” 中也只有该函数的声明 , 而没有定义函数的实现, 那么 , 是在哪里实 “printf” 函数的呢 ?最后的答案是 : 系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了 , 在没有特别指定时 ,gcc 会到系统默认的搜索路径“/usr/lib” 下进行查找 , 也就是链接到 libc.so.6 库函数中去 , 这样就能实现函数 “printf” 了 , 而这也就是链接的作用
我们的函数库分为静态库与动态库两种
静态库是指编译链接时 , 把库文件的代码全部加入到可执行文件中 , 因此生成的文件比较大 , 但在运行时也就不再需要库文件了。其后缀名一般为“.a”动态库与之相反 , 在编译链接时并没有把库文件的代码加入到可执行文件中 , 而是在程序执行时由运行时链接文件加载库, 这样可以节省系统的开销。动态库一般后缀名为 “.so”, 如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后 ,gcc 就可以生成可执行文件 , 如下所示。gcchello.o –o hellogcc 默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
静态库在编译连接时,将库中的代码全都加到了可执行文件中,这就导致了使用静态库的文件较大,但是好处就是运行时速度会更快,因为不需要再去其他地方访问动态库了,静态库的后缀一般为.a
动态库,顾名思义,函数库是动态的,每个文件需要使用函数库时再来动态访问,我们的文件在编译链接时要去别的地方访问动态库,这样可以节省系统空间,生成的可执行程序小,但是也相对而言效率低,动态库的后缀一般为.so
gcc 选项-E 只激活预处理 , 这个不生成文件 , 你需要把它重定向到一个输出文件里面-S 编译到汇编语言不进行汇编和链接-c 编译到目标代码-o 文件输出到 文件-static 此选项对生成的文件采用静态链接-g 生成调试信息。 GNU 调试器可利用该信息。-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库 .-O0-O1-O2-O3 编译器的优化选项的 4 个级别, -O0 表示没有优化 ,-O1 为缺省值, -O3 优化级别最高-w 不生成任何警告信息。-Wall 生成所有警告信息。
Linux有两种库,一种是静态库(libXXXX.a),一种是动态库(libXXXX.so),gcc静态链接时,默认为动态链接,一般链接的时候找的库默认.so,如果给后面加-static,变成静态链接,找的库就是.a所以,用户在链接时候如果出现了链接错误,应该先确认是否存在对应的库
g++
我们的g++与gcc在对文件的编译连接时步骤都是一样的
都是-E生成.i文件,-S生成.s文件,-c生成.o,而后用static调用静态库也都是一样的
Linux调试工具-gdb
我们在我们的vs下调试的方式就是直接打断点F10,F11进行调试的,而在我们只能使用命令行中的Linux中,是通过什么方式来进行操作的呢?
所以我们引入了我们的gdb,在我们了解gdb之前呢,我们先要明确程序的两种发布方式
debug:程序是在程序员手中,会加入很多调试信息,便于调试
release:不添加调试信息,自动对代码进行优化,发布版本
而我们在Linux中,gcc/g++默认生成的可执行程序是release版本的,无法被调试,若想生成debug版的,就需要在gcc/g++生成可执行程序时加上-g
我们可以看到,两次生成的tet.g文件的大小是不一样的
gdb的使用
list / l 行号:显示 binFile 源代码,接着上次的位置往下列,每次列 10 行。list / l 函数名:列出某个函数的源代码。r 或 run :运行程序。n 或 next :单条执行。s 或 step :进入函数调用break(b) 行号:在某一行设置断点break 函数名:在某个函数开头设置断点info break :查看断点信息。fifinish :执行到当前函数返回,然后挺下来等待命令print(p) :打印表达式的值,通过表达式可以修改变量的值或者调用函数p 变量:打印变量值。set var :修改变量的值continue( 或 c) :从当前位置开始连续而非单步执行程序run( 或 r) :从开始连续而非单步执行程序delete breakpoints :删除所有断点delete breakpoints n :删除序号为 n 的断点disable breakpoints :禁用断点enable breakpoints :启用断点info( 或 i) breakpoints :参看当前设置了哪些断点display 变量名:跟踪查看一个变量,每次停下来都显示它的值undisplay :取消对先前设置的那些变量的跟踪until X 行号:跳至 X 行breaktrace( 或 bt) :查看各级函数调用及参数info ( i) locals :查看当前栈帧局部变量的值quit :退出 gdb
make/makefile--项目管理
make是一个命令,而makefile是一个文件,通常该文件会在当前工作目录下存放
会不会写 makefifile ,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中, makefifile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作makefifile 带来的好处就是 ——“ 自动化编译 ” ,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。make 是一个命令工具,是一个解释 makefifile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的 make , Visual C++ 的 nmake , Linux 下 GNU 的 make 。可见, makefifile 都成为了一种在工程方面的编译方法。make 是一条命令, makefifile 是一个文件,两个搭配使用,完成项目自动化构建。
我们为什么要存在make,makefile
在vs中,项目管理(多文件管理)是vs帮助我们进行管理的,而在Linux中,用以维护项目文件关系的工作,是需要让make,makefile来完成的
什么是make,makefile
make是执行依赖关系和依赖方法的命令,makefile是维护该机制的文件
呢吗什么是依赖关系与依赖方法呢?
依赖关系和依赖方法
我们用一个例子来对其进行说明
依赖关系: 在这些关系中,因为test.o文件是由test.c文件通过预处理,编译以及汇编之后生成的文件,所以test.c文件的改变会影响test.o,我们就可以称test.o文件依赖于test.c
依赖方法:也就是上面的预处理,编译等,a生成b文件的方法,对于b而言,就是b依赖于a的方法
多文件编译
在我们呢vs中,编译文件是可以一起编译的,而在我们Linux中呢?我们目前只学习了单文件编译,难道要一个一个编译吗?这肯定不是的,我们的Linux也是可以进行多文件编译的
首先我们是可以直接对多个文件源进行编译的
生成的这个mytest就是可执行程序
但其实进行多文件编译时一般不采用源文件直接生成,而是先用每个源文件生成各自的二进制文件,再将这些二进制文件通过编译链接生成可执行程序
原因:当我们对其中某一个源文件进行了修改,我们只需要新编译生成该源文件的二进制文件
但其实随着文件个数的增加,每次重新生成可执行程序时,输入长度也会增加,此时我们就可以用上make与Makefile了
我们先创建一个Makefile,而后进入编写其依赖方法与依赖关系
而后在命令行当中输入make
我们就生成了可执行程序以及中间产物
其实还有简写
我们还能进一步再简化,可以利用通配符来表示,在多个文件的依赖方法和对象都相似时,利用通配符%来减少工作量,这样就可以不用一个个写出每个文件的生成规则了
伪对象 PHONE:[命令]
PHONE:[命令]
声明伪对象,无论对象是否最新,都会重新生成
因为这个clean没有被第一个目标文件直接或者间接关联,所有他的语句不会自动执行,需要在make后面加上这个伪目标才会执行,如make clean
通常需要生成的程序不会设置伪对象,因为每个项目的构建需要很长的时间,尽可能判断不需要生成就不用重新生成
但是因为工程是需要被清理的,我们就可以将这种clean的目标文件设立为伪目标,因为总是被执行的。
make原理
make 是如何工作的 , 在默认的方式下,也就是我们只输入 make 命令。那么,1. make 会在当前目录下找名字叫 “Makefifile” 或 “makefifile” 的文件。2. 如果找到,它会找文件中的第一个目标文件( target ),在上面的例子中,他会找到 “hello” 这个文件,并把这个文件作为最终的目标文件。3. 如果 hello 文件不存在,或是 hello 所依赖的后面的 hello.o 文件的文件修改时间要比 hello 这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成 hello 这个文件。4. 如果 hello 所依赖的 hello.o 文件不存在,那么 make 会在当前文件中找目标为 hello.o 文件的依赖性,如果找到则再根据那一个规则生成hello.o 文件。(这有点像一个堆栈的过程)5. 当然,你的 C 文件和 H 文件是存在的啦,于是 make 会生成 hello.o 文件,然后再用 hello.o 文件声明make的终极任务,也就是执行文件 hello 了。6. 这就是整个 make 的依赖性, make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么 make 就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。8. make 只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
项目清理
工程是需要被清理的像 clean 这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make 执行。即命令 ——“make clean” ,以此来清除所有的目标文件,以便重编译。但是一般我们这种 clean 的目标文件,我们将它设置为伪目标 , 用.PHONY 修饰 , 伪目标的特性是,总是被执行的。
此时我们的文件就被清理掉了
Linux小程序-进度条
行缓冲区
在我们开始写这个进度条前,我们先来了解下行缓冲区的概念,我们先来看一段代码
如我们所预料的那样,程序先输出hello world,而后停滞3秒,那么我们将其做一点改变呢?
我们将\n去掉了,我们的程序就变成了先停滞3秒,而后输出hello world,这是为什么呢?
这其实就涉及到我们行缓冲区的概念了,我们的任何语言在程序运行的时候,默认永远都是从上往下依次执行的,除非for,函数,if等,一定是先执行的printf(字符串被写入了c程序的缓冲区中,但并没有被输出!),在执行sleep,sleep结束,缓冲区内容被刷新,才能看到缓冲区的字符,而我们显示器对应的行刷新需要走到\n或者缓冲区满才会被打印,第二份代码中没有\n,所以字符串的内容直接被写到缓冲区当中,休眠结束
\r与\n
我们在先前学习过
\r代表的是回车,回到光标本行首
\n代表的是换行,使光标下移一行
我们的Enter键代表的就是\n+\r
所以我们就可以得出,当我们在显示器上输出字符而后直接回车再输出,第一次输出的就直接被覆盖了,所以我们是可以编写一个进度条前后覆盖的
这是我们的进度条代码
此时我们的进度条便可以完美的跑出