1、编辑器
1.1 vim 编辑器的安装
离线状态下:
dpkg -i vim.deb 离线安装
dpkg -r vim.deb 离线卸载
dpkg -r -p 连同配置文件一起删除软件
在线状态下:
sudo apt-get install vim 在线安装
apt-get remove vim 在线卸载
apt-get update 更新软件源列表
apt-get upgrade 更新软件
1.2 vim 的使用
形式:vim 文件名------假如文件存在 直接打开;假如文件不存在 创建文件
同时打开多个文件:vim file1 file2 file3.....
vim形式下打开的文件:
vim 创建的文件中,让每行程序前面显示行号:
① 输入指令:cd /etc/vim
② 输入指令:sudo vim vimrc
③ 按G跳转到最后一行,输入 set nu,然后 shift zz 退出
④ 然后 vim 打开的文件即可显示行号
vim 的配置:配置文件 /etc/vim/vimrc
1.3 vim 的工作模式
1.3.1 命令模式
通过 vim 打开的文件 默认进入的模式就是命令模式。
编辑文件内容后,回到命令行模式按Esc
① 文本删除操作(即 delete 删除)
d0:删除光标所在位置到行首间的字符(光标闪烁处的字符不被删除)
比如:左顶格的语句#include<stdio.h> 当光标在 > 上闪烁时,执行 d0 命令后,此时 > 没有被删除
D或者d$:删除光标到行尾间的内容(光标闪烁处的字符也被删除)
dd:删除光标所在行的内容,同时后面的行内容会向前挪一行(即删除内容的空行不被保留)
(n)dd:删除光标所在行的内容及光标下面n-1行的内容(n为行数),同时后面的行内容会向前挪一行(即删除内容的空行不被保留)
(n)x:删除光标后的字符(n代表向右要删除的字符数)
(n)X:删除光标前的字符(n代表向左要删除的字符数)
② 文本复制操作
yy:复制光标所在的行(包括内容或空行都可复制)
(n)yy:复制光标所在的行及光标下面n-1行的内容(包括内容或空行都可复制)
p:将复制的内容粘贴到光标所在行的下一行
u:撤销操作(undo 撤销)
ctrl+r:反撤销(redo 重做)
shift zz:保存并退出vim编辑器
③屏幕的翻页操作
ctrl+d:向后滚动半屏(内容向上拉)
ctrl+u:向前滚动半屏(内容向下拉)
ctrl+f:向后滚动一屏(内容向上拉)
ctrl+b: 向前滚动一屏(内容向下拉)
向下移动n行: n+enter
0:光标跳到所在行的行首
$:光标跳到所在行的行尾
n+G:跳到某一行(n为程序的行号,比如n=2时,则跳转到第二行)
gg:跳到文件的开始位置(光标跳到文件首行的行首)
G: 跳到文件的末尾(光标跳到文件最后一行的行首)
gg=G:代码对齐(对齐的是 Tab 键下的代码)
1.3.2 插入模式
此模式主要用来编写程序内容:以下指令切换时,需按 Esc 回到命令行,然后输入新指令
i:将内容插入到光标的前面(insert 插入)
I:将内容插入的到光标所在行的行首(大写i)
a:将内容添加到光标的后一位(按下a 后,光标向后挪一位,然后内容在光标的前面插入)(add 添加)
A:将内容添加到光标所在行的行尾(此时光标闪烁处没有字符,然后内容在光标的前面插入)
o:将内容插入到光标所在行的下一行(新增加一空白行,然后在光标前面插入内容)(open new line 插入新行)
O:将内容插入到光标所在行的上一行(新增加一空白行,然后在光标前面插入内容)
1.3.3 底行模式
由命令模式切换到底行模式:先输入冒号,再输入指令
w:保存内容但不退出
w!:强制保存,不退出
q:直接退出,不保存内容
q!:强制退出,不保存内容
wq:保存内容并退出
wq!:强制保存并退出
字符串的查找:
/+字符串 (键入一个斜杠,然后输入要查找的字符串,enter。之后按 n 向下查找字符串;按 N 向上查找字符串)
n:表示向下查找
N:表示向上查找
?字符串(操作方法同上)
n:表示向上查找
N:表示向下查找
字符串的替换:
:%s/源串/目标串 :将当前文件中所有行的第一个源串改为目标串
:%s/源串/目标串/g :替换文本中的所有的源串为目标串
1.3.4 视图模式
在命令行模式下 按 v 即可进入视图模式(按上下左右(或HJKL)可以明显看出所选中的内容)
d:删除 y:复制 x:剪切
2、编译器
程序编译流程:编译预处理----编译器----汇编器----链接----生成可执行程序
编译器的作用:将代码文件编译成机器可以识别的二进制文件
预处理:处理伪指令(#)和特殊符号(头文件展开、宏定义替换、条件编译、头文件包含)
伪指令: 宏定义、头文件包含、条件编译
预处理 -E gcc -E main.c -o main.i
编译:---转汇编 -S gcc -S main.i -o main.s
汇编:---转二进制 -c gcc -c main.s -o main.o
链接库:生成可执行文件 gcc main.o -o main
-o:指定输出的文件名 有两种方式:gcc main.c -o main 或者 gcc -o main main.c
-c:只编译不链接 gcc -c main.c -o main.o
-g:产生GDB的调试信息,主要用来调试代码
gcc main.c -g 编译 main.c 生成可以调试的可执行程序 a.out
对以上编译过程概念的解释:
汇编:汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句对应一条机器指令
链接:头文件只是函数声明,实现封装在库文件中,链接就是找到指定路径下的库文件
3、库(静态库/动态库)
什么是库:包含了通用函数的数据和二进制的可执行机器码的文件
库的分类:静态库 .a 动态库 .so
使用库文件的特点:可移植性、封装性、保护源码(自己开发的软件想让别人用,但又不想让别人知道源代码)
动态库和静态库的区别:
静态库:
① 静态库在编译的时候直接将库文件编译到可执行程序里。(静态库是多个 .o 文件的集合)
② 因为整个函数库的所有数据都会被整合进目标代码中,所以静态函数库编译成的文件比较大,优点是编译后的执行程序不需要外部的函数库支持(即静态库一旦编译成功之后,在运行的时候就和自己的库函数没有关系了);缺点是,如果所使用的静态库发生更新改变,则程序必须重新编译
动态库:
① 动态库在编译的时候并不会将库文件编译到可执行程序里,而是在程序执行的时候 动态的去 lib或者是usr/lib下,去寻找需要的库文件(动态库又称共享库,产生的可执行文件较小)
② 缺点是因为函数库并没有整合进程序,所以程序的运行环境必须提供相应的库。优点是动态库的改变并不影响你的程序,所以动态函数库升级比较方便
3.1 静态库的创建
① 准备功能文件: main.c func1.c func2.c
② 只编译不链接:
gcc -c func1.c -o func1.o
gcc -c func2.c -o func2.o
③ 打包生成静态库:(格式:ar rc lib静态库名.a 功能文件名.o)
ar rc libmyfunc.a func1.o func2.o
④ 利用静态库编译程序:(格式:-l静态库名)
gcc main.c -o main -lmyfunc -L ./
-lxxx:代表的是库名
-l:指定依赖的库(你所有的库的头文件路径)
-L:指定库文件所在的位置(即指定你的库文件路径)
⑤ 直接执行程序:./main
3.2 动态库的创建
3.2.1动态库创建方法一
① 准备功能文件:main.c func1.c func2.c
② 只编译不连接:
gcc -fPIC -shared -c func1.c -o func1.o
gcc -fPIC -shared -c func2.c -o func2.o
③ 打包生成动态库:
gcc -fPIC -shared func1.o func2.o -o libmyfunc.so
④ 利用动态库编译程序:
gcc main.c -o main -lmyfunc -L ./
⑤执行可执行程序:
在执行的时候 它默认会去/lib或者 /usr/lib里去找myfunc库 就需要你将这个库文件放入lib或者 usr/lib下 此时:sudo cp libmyfunc.so /lib (下放管理员权限,将动态库复制到/lib库中)
⑥ 直接执行程序:./main
3.2.2 动态库创建方法二
① 准备功能文件:main.c func1.c func2.c
② 只编译不链接:
gcc -fPIC -shared -c func1.c -o func1.o
gcc -fPIC -shared -c func2.c -o func2.o
③ 打包生成动态库:
gcc -fPIC -shared func1.o func2.o -o libmyfunc.so
④ 将编译生成的动态库 放到lib下
⑤ 利用动态库编译程序:
gcc main.c -o main -lmyfunc
⑥ 直接执行程序:./main
3.2.3动态库创建方法三
① 准备功能文件:main.c func1.c func2.c
② 只编译不链接:
gcc -fPIC -shared -c func1.c -o func1.o
gcc -fPIC -shared -c func2.c -o func2.o
③ 打包生成动态库:
gcc -fPIC -shared func1.o func2.o -o libmyfunc.so
⑤ 利用动态库编译程序:
gcc main.c -o main -lmyfunc -L ./
④ 修改环境变量:
/etc/profile 加上一句话 export
⑥ 直接执行程序:./main
4、GDB调试工具
GDB是Linux系统下的程序调试工具:主要用来发现代码问题、调试代码
代码出现bug之后:① 测试 发现代码中的bug(测试写的代码是否安全可靠)
② 固化 让bug重现(让程序重现错误)
③ 定位 确定bug出现的位置
④ 纠正 修改bug(修复代码中的错误)
⑤ 验证 再次测试 bug 是否解决
GDB主要完成四方面功能:
(1)、启动自己的程序,可以按照自己的要求随心所欲地运行程序;
(2)、让需调试的程序在自己指定的调试断点处停住(断点可以是条件表达式);
(3)、当程序被停住时,可以检查此时程序中所发生的情况;
(4)、动态地改变自己程序的执行环境。
要想使用GDB调试工具,必须要求自己的可执行程序里有GDB的调试信息,即在编译代码的时候加上 -g
启动GDB:gdb 可执行程序
示例:① gcc main.c -o main -g
② gdb ./main
③ G 跳转到最后一行
GDB常用指令:
l:列出源代码,接着上次的位置往下列(或 list)
list 行号:列出从第几行开始的源代码
list 函数名:列出某个函数的源代码
r:运行被调试的程序,如果没有断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。(或 run)
b 行号:在某一行设置断点(即breakpoint 断点)(断点要设置在有程序语句的地方,要设置的有意义)
info b:查看所有断点信息
where:假如代码出现段错误,可以通过 where 定位段错误的位置
cont:继续运行程序 直到下一个断点(continue 继续)
d 断点号:删除断点(即delete)
disable 断点号:失能断点(断点信息 y 变 n)
enable 断点号:使能断点(断点信息 n 变 y)
clear 行号:清除某一行的断点
p 变量名:打印当前变量的值(printf 打印)
start:启动按步调试(停在main函数第一行语句前面等待命令)
next:一步一步的执行程序(或 n)
遇到函数调用 会将这个函数执行完(即直接得到这个函数的结果)
step:一步一步的执行程序(step 不要用在 printf 中,printf也是一个函数,step 进入到这个函数后,会打印出意料之外的内容)(或 s)
遇到函数调用 会进入到函数的内部一步一步的执行
finish:退出按步调试
quit:退出gdb的调试(或 q)
GDB调试流程:
① 先创建一个C文件:vim main.c
② 编译C文件:gcc main.c -o main -g (此时出现 main 可执行文件)
③ 运行可执行文件:gdb ./main
④ 键入list 指令,系统开始从第一行列出源代码,一次只列出10行,如果要从第11行开始继续列源代码可以通过 enter 键重复上一次执行的指令。
⑤ 键入各种指令操作
5、make 工具
make:脚本语言,实现编译代码的自动化。 make 他会默认的去找makefile
makefile 的意义:执行make的时候,makefile 告诉 make 怎样去自动化地编译代码,makefile文件中描述了整个工程所有文件的编译顺序、编译规则
makefile 的组成:由依赖生成目标的规则 (命令)
一个最简单的 makefile 要包含三项:目标、依赖、规则
目标 依赖
main:main.o
gcc main.o -o main(前方的空格为一个 Tab 键)(规则语句)
make 是一个命令工具,它解释 Makefile 中的指令(或者说是规则),它能够比较容易的构建属于自己的工程,整个工程的编译只需要一个make命令就可以完成编译、链接生成可执行文件。
当使用 make 工具进行编译时,工程中以下几种文件在执行 make 时将会被编译(重新编译):
(1) 所有的源文件没有被编译过,则对各个 C 源文件进行编译并进行链接,生成最后的可执行程序;
(2) 每一个在上次执行 make 之后修改过的 C 源代码文件在本次执行 make 时将会被重新编译;
(3)头文件在上一次执行 make 之后被修改。则所有包含此头文件的 C 源文件在本次执行 make 时将会被重新编译。
makefile 的使用:
① 先创建一个C文件:vim main.c
② 创建一个 makefile 文件(并在里面编写编译规则):vim makefile
一个规则可以有多个命令行,每一条命令占一行,每一个命令行必须以[Tab]字符开始, [Tab]字符告诉 make 此行是一个命令行,可以将一个较长行使用反斜线( \)来分解为多行。所有的命令行必需以[Tab] 字符开始,但并不是所有的以[Tab]键出现行都是命令行。
makefile可以有多个目标:如果如果目标文件所依赖的文件不存在当前的指令,那么他就继续往下找,直到找到所依赖的文件位置
makefile 里的注释:#
特殊的宏:
$@:目标文件
$^:所有的依赖文件
$<:第一个依赖的文件
makefile的主目标和次目标:
主目标:最上边的目标
次目标:跟主目标同级 并且没有依赖关系的目标
假如有 makefile Makefile mk,系统会默认找到第一个 makefile,但是如果想要使用mk规则,则可以指定要使用的规则:make -f mk
makefile 伪目标:
它不代表一个真正的文件名,在执行 make 时可以指定这个目标来执行其所在规则定义的命令,有时也可以将一个伪目标称为标签。使用伪目标有两点原因,第一是避免在我们的 Makefile 中定义的只执行命令的目标(此目标的目的为了执行一些列命令,而不需要创建这个目标)和工作目录下的实际文件出现名字冲突。第二是提高执行 make 时的效率
1、常见的 clean 目标形式:
clean:
rm *.o temp
规则中“ rm”不是创建文件“ clean”的命令,而是删除当前目录下的所有.o 文件和 temp文件。当工作目录下不存在“ clean”这个文件时,我们输入“ make clean”,“ rm *.o temp”总会被执行。
删除生成的中间产物:你执行make的时候clean不会自动执行,需要你手动输入make clean
2、声明伪目标,clean”的完整书写格式应该如下:
.PHONY: clean
clean:
rm *.o temp
将一个目标声明为伪目标的方法是将它作为特殊目标”.PHONY”的依赖,当目标被声明为伪目标后, make 在执行此规则时不会去试图去查找隐含规则来创建它。
示例: