Linux基础-Linux的编辑器、编译器、库、gdb调试
Linux编辑器
gedit编辑器
- gedit是一个Linux环境下的文本编辑器,类似windows下的写字板程序(右击新建文本文档),在不需要特别复杂的编程环境下,作为基本的文本编辑器比较合适。
- 使用:
gedit 1.txt
- 创建一个1.txt文件在gedit环境下编辑。
VI编辑器
vi介绍
- vi 编辑器是 Linux 系统中最常用的文本编辑器,vi 在Linux界有编辑器之神的美誉,几乎所有的 Linux 发行版中都包含vi程序。
- vi 工作在字符模式下,不需要图形界面,非常适合远程及嵌入式工作,是效率很高的文本编辑器,尽管在 Linux 上也有很多图形界面的编辑器可用,但vi的功能是那些图形编辑器所无法比拟的。
- vim 是 vi 的升级版,它不仅兼容 vi 的所有指令,而且还有一些新的特性,例如 vim 可以撤消无限次、支持关键词自动完成、可以用不同的颜色来高亮你的代码。vim 普遍被推崇为类 vi 编辑器中最好的一个。
vi三种工作模式
- 命令模式:
- 执行命令,用来运行一些编排文件、存档以及离开vi等操作命令。
- 当执行 “vi 文件名” 后,首先进入命令模式,此时输入的任何字符都被视为命令。
- 比如输入
i
则进入编辑模式
- 输入模式(也叫插入模式/编辑模式):
- 用于输入字符。
- 在命令模式下,键盘键入i可以进入该模式
- 键入esc则返回命令模式
- 末行模式:
- 在命令模式下输入”:“则就进入末行模式了,可以在末行输入命令,回车,则执行命令
- 如果输入了”: xxx”,想要返回命令模式,则按2次esc即可切入到命令模式
- 注意:编辑模式不能直接切换到末行模式!
vi最基本操作
- 打开文件
vi filename
:打开或新建文件,并将光标置于第一行行首,如果文件不存在,则会新建文件。
- 编辑文件
- 如果通过vi打开一个已经存在的文件,首先进入命令模式,此时输入的任何字符都被视为命令,不能输入内容。
- 按i既可以进入插入模式,可以编辑内容。按esc即可退出插入模式,进入命令模式。
- 保存文件
- 一定要先退出插入模式(按Esc进入命令模式),然后,
shift + zz (按住 “shift” + 按两下“z”键)
即可保存退出当前文件。
- 一定要先退出插入模式(按Esc进入命令模式),然后,
常用命令
- 命令模式下常用的命令:
-
光标的位置:(hjkl)
hjkl:正好在键盘上连续的4个键 h:光标往前移动 l:光标往后移动 j:光标向下移动 k:光标向上移动 0:光标移动到行首 $(shift+4): 光标移动到行尾部 gg:光标移动到文件开始位置 shift + g:光标移动到文件最后一行开始位置
-
删除
x:删除光标位置的字符 nx:删除光标后n个字符 X: 删除光标位置前面的字符 nX:删除光标前n个字符 dw: 删除整个单词(将光标移动到单词第一个位置) d0:删除光标前面所有的字符 d$(或者shif+d,即D):删除光标后面所有的字符 dd:删除光标所在的行 ndd:从光标开始的哪一行,连续删除n行
-
撤销
u:撤销删除 ctrl+r:反撤销
-
复制、粘贴(注意:vi中的删除不是删除,而是剪切)
p: 粘贴到光标所在行下面 P(大写):粘贴到光标所在行 yy:复制光标所在行 npp:复制光标所在行的n行
- 可视模式、查找
- 目的:想要复制、删除某一段内容
- 步骤:
- 输入
v
进入可视模式 - 通过:
hjkl
移动原则目标内容 - 输入
d
删除或者y
复制选中的内容 - 将光标移动到某个位置,按下
p
粘贴即可
- 输入
-
查找
/+查找内容: 从光标位置向下查找,然后输入回车,接着输入n,切换查找到的每一个内容 ?+查找内容:从光标位置向上查找
-
缩进
<< : 向左缩进 >> : 向右缩进
-
保存退出
ZZ(shift+z+z) 保存退出
-
- 编辑模式
-
主要是怎样从命令模式下进入编辑模式(简记: 啊 ios)
a 光标位置右边插入文字 A 光标所在行尾插入文字 i 光标位置前面插入文字 I 光标所在行首插入文字 o(字母) 光标位置下方开启新行 O(字母) 光标位置上方开启新行 s:删除光标所在的那个字符,然后插入文字 S:删除光标所在行的内容,然后插入文字
-
- 末行模式
- 命令模式下输入”:”进入末行模式
-
替换
:n+回车: 直接跳转到n行 :s/p1/p2 将当前行中定义一个p1用p2替代 :s/p1/p2/g 将当前行中所有p1均用p2替代 :g/p1/s//p2/g 将文件中所有p1均用p2替代 :n1,n2s/p1/p2/g 将n1到n2行中所有p1均用p2替代
-
保存、退出
:wq 保存退出 :x(小写) 保存退出 :w filename 保存到指定文件 :q 退出,如果文件修改但没有保存,会提示无法退出 :q! 退出,不保存 :!命令 暂时离开vi,执行命令
-
set命令
:set ic 搜寻时忽略大小写 :set noic 搜寻时不忽略大小写 :set nu 显示行号 :set nonu 不显示行号
-
分屏
:sp 上下分屏 ctrl+ww光标上下切换 :vsp 垂直分屏
Linux编译器-gcc
- 简介
- gcc是linux下的一款文本编译器。
-
gcc编译的4个阶段
- 预处理
- 把头文件展开
- 宏替换,把代码中用到的宏都替换成内容。
- 删除注释
- 生产
.i
文件
- 编译
- 把
.i
文件编译成汇编文件.s
- 把
- 汇编
- 把汇编文件
.s
汇编成二进制文件.o
- 把汇编文件
- 链接
- 把所有的
.o
文件放到一起,打包成可执行程序
- 把所有的
-
命令示例:
gcc -E add.c -o add.i //预处理 gcc -S add.i -o add.s //编译 gcc -c add.s -o add.o //汇编 gcc add.o -o app //链接 ./app //执行
- 预处理
-
gcc常用的参数
-I 头文件路径: 当sum.c导入的后文件不在同一目录下时,需要指定头文件的路径:-I 头文件路径,比如: gcc sum.c -I ./include -o app -D 宏名: 当我们需要调试程序,在某个宏存在的时候才会输出时(条件编译),比如: gcc sum.c -I ./include -D DEBUG -O+数字:有3个等级1、2、3,代码的优化程度,比如: gcc sum.c -I ./include -D DEBUG -O3 -Wall: 编译时输出警告信息 -g: 程序输出调试信息
-
代码举例:
#include<stdio.h> int main(){ int a = 10; int b = 20; int c = a+b; //没有使用-D DEBUG,则执行是不会输出sum=30 #ifdef DEBUG printf("sum=%d",c); #endif return 0; }
库
静态库
- linux中静态库的命名规则:
lib+库名+.a
- 静态库的制作
- 生成对应的
.o
- 将生成的
.o
文件打包:ar rcs + 生成的静态库的名字(libmytest.a)+ 生成的所有的.o
- 生成对应的
- 发布和使用静态库(提供给用户使用)
- 静态库
- 头文件
- nm命令
- 使用nm命令可以查看.a文件是由哪些.o文件组成:
nm 静态库
- 使用nm命令可以查看可执行文件内容:
nm 可执行文件
- 使用nm命令可以查看.a文件是由哪些.o文件组成:
- 使用静态库的优缺点:
- 优点:
- 发布应用程序时不需要提供对应的库(已经打入到可执行文件中了)
- 库的加载速度快,因为生成可执行文件时,已经把相应的代码打入到了可执行文件中
- 缺点:
- 库被打包到应用程序中,导致应用程序很大。
- 库发生了改变,应用程序需要重新编译。
- 优点:
- 举例使用:
-
一个文件目录有如下文件
include //存放头文件文件夹,里面有个head.h lib //存放生成的库文件夹 src //存放源码文件夹,里面有个add.c main.c //主函数
-
生成静态库过程
gcc -c add.c -I ../include -o add.o //生成对应的.o文件 ar rcs libmytest.a ./src/add.o //将.o生成静态库 mv libmytest.a ./lib //将静态库移动到lib文件夹中
- 使用静态库
-
方法1:
gcc main.c lib/libmytest.a -o sum -I include //将静态库与main函数一起编译生成可执行文件 sum ./sum //执行
-
方法2:
gcc main.c -L ./lib -l mytest -o sum -I ./include /将静态库与main函数一起编译生成可执行文件 sum ./sum //执行 //解释:-L +动态库的路径 -l +动态库名称删掉lib剩余部分
-
-
main.c代码如下;
#include <stdio.h> #include "head.h" int main(){ int a = 10; int b = 20; int c = add(a,b); printf("%d",c); return 0; }
-
动态库
- 命名规则:
lib+库名字+.so
- 制作步骤
- 生成与位置无关的代码(生成与位置无关的.o):
gcc -fPIC -c *.c
- 将.o打包成动态库:
gcc -shared -o libMycalc.so *.o
- 生成与位置无关的代码(生成与位置无关的.o):
- 发布和使用(提供给用户)
- 动态库.so文件
- 头文件
- 动态库的优缺点
- 优点:
- 执行程序体积小
- 动态库更新了,不需要重新编译程序
- 缺点:
- 发布程序的时候,需要将动态库提供给用户
- 动态库没有打包到执行程序中,加载速度相对较慢
- 优点:
- ldd命令
- 用于查看可执行程序依赖的所有动态库:
ldd myapp
- 用于查看可执行程序依赖的所有动态库:
- 举例使用
- 目录仍然同静态库
-
生成动态库过程
gcc -fPIC -c ./src/add.c -I ./include //生成与位置无关的.o gcc -shared -o libMycalc.so ./src/add.o -I ./include //将.o打包成动态库
-
使用动态库
-
方法1:
gcc main.c lib/libMycalc.so -o app -I ./include //将动态库与main函数一起编译生成可执行文件 app ./app //执行
-
方法2:
gcc main.c -L ./lib -l Mycalc -o myapp -I ./include ./myapp //执行
-
注意这种方法执行会报错:
./myapp: error while loading shared libraries: libMycalc.so:cannot open shared object file: No such file or directory
-
使用ldd命令查看:
ldd myapp
linux-vdso.so.1 (0x00007fff00b97000) libMycalc.so => not found //linux下的标准C库 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff6fe65d000) //动态链接器,本质也是一个动态库,上面3个动态库都是通过这个链接器加载的。 /lib64/ld-linux-x86-64.so.2 (0x00007ff6fec50000)
- 原因:
- 可执行程序在调用动态库的时候并不是由可执行程序直接调用动态库的,而是需要一个程序来帮助调用这个动态库,这个程序叫做动态链接器。
- 动态链接器会帮助可执行程序自动调用需要使用的动态库
- 动态连接器本质也是一个动态库,就是这个东西
ld-linux-x86-64.so.2
- 那么这个动态连接器查找动态库的规则是什么呢?
- 根据环境变量
-
查看环境变量都有哪些:
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
- 也就是说,动态连接器会通过这些路径一个一个遍历查找相应的动态库,所以查找不到。
- 解决办法:
- 方法1:
- 复制到系统的
/lib
目录中(尽量不要使用)sudo cp ./lib/libMycalc.so /lib
- 复制到系统的
- 方法2:(临时测试)
- 使用LD_LIBRARY_PATH,临时环境变量
- 作用:指定查找共享库(动态库)时除了默认路径之外的其他路径
- 该路径在默认路径之前查找
- 通过系统环境变量LD_LIBRARY_PATH设置库的目录,然后导入
- 但是这种方法是零时的,即关闭终端,下次再执行的时候还是找不到动态库
终端输入: export LD_LIBRARY_PATH=./lib
- 使用LD_LIBRARY_PATH,临时环境变量
- 方法3:(永久设置)
- 可以设置到当前用户的bash配置文件
- cd回车,进入到当前用户的根目录,
ls -a
,显示所有文件包括隐藏.bashrc
就是 vi .bashrc
打开,在最后一行输入:export LD_LIBRARY_PATH=/home/coderzhong/桌面/demotest/lib
,然后关闭终端,再次打开就可以了
- 方法4:(必须掌握)
- 找到动态连接器的配置文件
cd /etc
然后ls 找到ld.so.conf
- 将动态库的路径写到配置文件中
vi ld.so.conf
- 添加动态库的绝对路径:
/home/coderzhong/桌面/demotest/lib
:wq
回车即可
- 更新:
sudo ldconfig -v
-
此时再次:
ldd myapp
如下:linux-vdso.so.1 (0x00007fff51392000) libMycalc.so => /home/coderzhong/桌面/demotest/lib/libMycalc.so (0x00007f0125deb000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f01259fa000) /lib64/ld-linux-x86-64.so.2 (0x00007f01261ef000)
- 找到动态连接器的配置文件
- 方法1:
-
-
gdb调试
- 生成带调试信息的可执行文件:
gcc *.c -o app -g
-g
: 可以进行调试,但是文件比较大相对于不带-g
- 启动gdb:
gdb app
- 查看程序源代码:
- 直接输入
l
,list简写,默认显示包含main函数的那个文件源码,回车,查看剩余内容 l n(函数名)
,当前文件第10行(函数名对应的)代码- 查看其它文件的源代码:
l test.c:20
,查看test.c的第20行内容 l test.c:sum
,查看test.c中sum函数内容,只列出一部分,输入l
回车会继续展示其它内容。
- 直接输入
- 设置断点
- 普通断点:
break n
:在第n行打断点,break 可以简写成b - 条件断点:
b 15 if i==15
:在第15行打断点,如果i等于15才会断点。
- 普通断点:
- 查看断点
info b
: 查看断点信息,info可以简写成i
- 删除断点
d n
,n是断点对应的编号,可以用info b
查看所有断点定位的编号
- 启动程序
start
,启动后只会执行一步r
,run简写,启动后会直接定位到断点处,没有断点就会直接跑完
- 执行
n
,next简写,单步执行,遇见函数,不会进入函数体s
,step简写,单步执行,遇见函数,会进入函数体c
,continue简写,多步执行,直接执行到断点处
- 查看变量的值
p a
,查看变量a的值
- 查看变量类型
ptype a
,查看a的类型
- 设置变量的值
set var i=10
,将变量i设置为10
- 追踪某个变量的值
display i
,追踪变量i的值
- 删除追踪
undisplay n
,n代表追踪变量的编号,可以用info display
查看所有追踪变量的编号
- 跳槽单次循环
u
,跳出当前的for循环
- 退出当前函数体
finish
,从通过s
进入的函数体回到原来位置- 注意如果for循环中有断点必须先删除断点,在使用finish才能跳出循环
- 退出gdb :
quit