包安装器yum
yum的概念
yum就是一个应用商店,里面有经过yum源认证的软件包 如果程序员想用哪个包,可以使用yum搜索和安装 由于是从yum源下载到本地,所以必须要有网络
yum三板斧
yum list
查看yum都有哪些安装包 可以加上管道进行过滤 例如: yum list | grep “tree”
yum install [-y] [待要安装的软件包名称]
功能:安装某个软件
yum remove [待要卸载的软件包名称]
功能:卸载某个软件
lrzsz与xftp
lrzsz :支持文件的上传和下载
基本操作: lz: 将win机器的文件上传到Linux操作系统 sz: 将Linux下的文件下载到win机器
注意:lrzsz只支持文件的上传和下载,对于文件夹必须先压缩再上传
xftp:文件上传和下载的工具
与xshell是同源的
编辑器vim
常见的3种模式
正常模式
控制屏幕光标的移动,字符字或行的删除,移动复制某区段 进出 插入模式 和 底行模式
插入模式
只有在该模式下,在可以做文字输入 输入完毕后按下Esc 切换到正常模式 一般情况下,写代码是在该模式下完成的
底行模式
文件保存或退出 也可以进行文件替换,找字符串,列出行号等操作 在命令模式下,输入冒号即可进出该状态
模式之间的切换
我们在编程的过程中,离不开这三种模式,所以三者之间如何切换也是一大重点 具体切换过程以及方式如下图所示:
7字真言(正常模式下的快捷操作)
移(移动光标)
h j k l
h:光标向左移动 j: 光标向下移动 k:光标向上移动 l: 光标向右移动
上下左右键分别代表光标移动的方向 w :光标移动到下个字的开头 b :光标移动到上个字的开头 gg :进入到文本开始 G :移动到文章的最后 $ :移动到光标所在行的行尾 ^ :移动到光标配所在行的行首
删(删除)
x :每按一次,删除光标所在位置的一个字符
#x :表示删除光标所在位置后的#个字符(包括自身)
X :每按一次,删除光标所在位置的前面一个字符
#X :表示删除光标所在位置前的#个字符
dd :删除光标所在行
#dd :表示从光标所在行开始,删除#行
复(复制)
yy :复制光标所在行到缓冲区
#yy :从光标所在行开始,复制#行到缓冲区
p :将缓冲区的字符粘贴到光标所在位置
注意:所有与y有关的复制命令必须与p配合才能完成复制与粘贴功能
替(替换)
r :替换光标所在处字符 R :替换光标所到之处的字符,直到按下Esc 停止
撤(撤销)
u :回到上一个操作,按多次u可以执行多次恢复 Ctrl + r :撤销的恢复
更(更改)
cw :更改光标所在处的字到字尾处
c#w 更改#个字:
跳(跳转)
#G :移动光标至文章的#行行首
vimforcpp
一个为用户提供良好编程环境的软件~~ 安装方式: 在想要安装的用户命令行下输入 curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh 回车等待安装完毕,重启终端
多行注释&&多行去注释
多行注释
1、Ctrl + v 2、选中需要注释的行,使用h j k l移动光标 3、shift + i :进入插入模式 4、输入注释符号 5、Esc demo 注释12–15行内容 Ctrl + v
选中需要注释的行,使用h j k l移动光标 shift + i :进入插入模式 输入注释符号 Esc
多行去注释
1、Ctrl + v 2、选中需要去注释的行当中的注释字符,使用h j k l 移动光标 3、按下x 删除即可 demo 在上例的结果下去掉刚才注释的部分 1、2、两步结果 3、按下x删除
替换
- 单行首个目标字符串替换
s/[待替换的字符串]/[替换成为该字符串]/
- 单行全部目标字符串的替换
s/[待替换的字符串]/[替换成为该字符串]/g
- 全文替换
%s/[待替换的字符串]/[替换成为该字符串]/g
- 指定行替换
num1,num2 s/[待替换的字符串]/[替换成为该字符串]/g
结论 g :表示替换当前所有行 % :代表当前所有行
swp文件没有正常关闭应该如何处理
前提引入 试想一下当你正在写代码时,你的设备突然断网了,然后你查看原因后重新接入网络,这时候你再去打开刚在你编写的文件时,就会莫名其妙的出现无法打开的错误提示: 此时,怎么办?不必慌张,这就是非正常关闭设备而出现的swp文件。 那什么是swp文件呢? 这是vim在创建文件时创建的一个副本文件,它主要保存用户修改原文件之前的文件,用户的撤销等操作依赖于该副本文件。
好了,遇到这种情况该怎么办?
- 复制报错信息第一行双引号下的路径
- 按q,退出到命令行模式下
- rm + 复制的路径
回车之后。重新执行打开文件的命令,错误消失!
编译器gcc/g++
gcc与g++的区别
一般来说,gcc用来编译c语言的代码,也就是.c文件 g++用来编译c++的代码 但是g++也可以编译c语言的代码,即向下兼容
编译的四个过程
预处理
做什么事情? 宏替换、头文件展开、去注释、条件编译 执行语句
gcc -E [source file] -o [xxx].i
其中选项 -E :让gcc在预处理结束后停止编译过程 -o :目标文件 .i 文件表示已经过预处理的C原始程序
e.g 这是源代码 经过预处理后 test.i中有好多代码我们并没有编写,如下图,这些代码就是头文件展开的内容 我们通过G跳转到代码的尾部,找到了我们自己编写的代码,但是与当时写的还是有点出入 以上就是预处理所做的事情
编译
将源文件生成汇编代码
gcc -S test.c/test.i -o [xxx].s
e,g 对上例生成的test.i 文件进行编译,让其由C原始程序变为汇编程序 查看test.s文件,我们可以发现程序已经变成汇编代码了
汇编
将汇编代码转换成为二进制代码
gcc -c test.c/test.i/test.s -o test.o
e.g 对上例中生成的test.s进行汇编操作 查看test.o文件,我们发现里面的内容好像有点上头,完全看不懂是什么含义 其原因就是:此时代码已经是最底层的机器语言了,也就是有若干个0与1组成的序列,我们在用vim打开时,系统默认的将这些01代码转换为字符,所以我们看到的就是上图这种情况。
链接
将若干个二进制代码(.o 文件)或者库文件链接起来生成可执行程序或者库文件
gcc test.c/test.i/test.s/tesi.o -o mytest
e.g 在上例的基础上对test.o进行链接操作 此时mytest就是最终生成的可执行程序 执行结果如图所示
静态编译与动态编译
这是编译程序两种方式方法
动态编译
gcc test.i -o mytest 这条编译命令默认是动态编译的 下面介绍一个命令的含义:file + 可执行文件文件名 可以查看该文件的属性 紧接着介绍ldd命令:查看一个可执行程序链接的库文件 那么什么是符号表?符号表又有什么用处呢? 符号表实质上就是在链接过程中二进制文件中使用的库函数与库中对应函数所在位置二者之间形成的一张映射关系表。 可以简单理解为 在执行可执行程序遇到库函数时要先去符号表查对应函数在库中的位置,然后转到该位置执行该库函数。
静态编译
gcc test.i -o mytest -static 给命令后面加上-static,就表示是静态编译 此时mytest是动态编译的,mytest_static是静态编译的 我们发现,二者的大小差距很大,这是为什么呢? 原因是静态编译在编译的过程中将代码需要用到的库函数对应的库文件也编译到可执行文件当中去了。这样就会导致可执行文件比较大。
二者的优缺点
动态编译 优点:更加节省内存,适用于大规模的软件开发 缺点:不具有自完备性,依赖于相关库文件,速度比静态链接慢
静态编译 优点:代码装载速度快,执行速度略快与动态链接。在发布文件的时候不需要考虑用户个人电脑上是否有相关的库文件,因为它自带 缺点:文件体积大
调试器 gdb
debug与release
程序发布的两种方式debug与release 结论:
- 在Linux下debug版本的程序在编译的时候需要增加-g命令行参数
- 默认不加-g,则为release版本
调试的基础方法
gdb [binfile]
l: 查看源码,从main函数开始
l [function name] :查看某个函数的源码
r:让程序执行起来
n:逐过程,相当于F10
s:逐语句,相当于F11
b [行号]:
i b:查看断点
c:继续执行
delete breakpoints:删除所有断点
delete breakpoint n:删除序号为n的断点
disable breakpoint:禁用断点
enable breakpoint:启用断点
info locals:查看当前栈帧局部变量的值
p [变量名] : 查看变量的值
bt:展示调用的堆栈
可以通过调用堆栈来查看代码执行的函数调用关系
q: 退出
为了验证上述调试的命令,我们提前转备好了待调试代码,具体如下:
#include <stdio.h>
2
3
4 void Swap(int *xp,int *yp)
5 {
6 int temp = *xp;
7 *xp = *yp;
8 *yp = temp;
9 }
10
11
12 int main()
13 {
14 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
15 printf("arr[4] = %d\n",arr[4]);
16
17 int number = 100;
18 printf("number = %d\n",number);
19 int *p = &number;
20 printf("*p = %d\n",*p);
21
22
23 int num1 = 158;
24 int num2 = 167;
25 Swap(&num1,&num2);
26
27
28
29 struct Data
30 {
31 int age;
32 int score;
33 };
34
35 Data d;
36 d.age = 19;
37 d.score = 78;
38 printf("d.age = %d, d.score = %d\n",d.age,d.score);
39
40 Data *Id = &d;
41 printf("age = %d,score = %d\n",Id->age,Id->score);
42
43 return 0;
44 }
调试前提(***)
现在开始我们调试命令的测试: 首先,编译生成一个可执行程序 紧接着调用gdb命令gdb [binfile] 进入调试状态 此时,我们发现无法成功进入调试模式!!!显示没有调试信息。
究其原因,是因为我们上面生成的可执行程序是release版本的,无法调试。 要想调试一个程序,生成的可执行程序版本必须是debug版本~~
因此,我们使用 -g 命令选项生成debug版本的可执行程序 接着调用gdb命令gdb [binfile] 进入调试状态
l / l [函数名] 查看源码
查看某个函数的源码
r 让程序执行起来
问题:在执行gdb 【filename】 命令后,程序开始执行了吗?? 并没有,我们需要执行 r 命令,让程序执行起来。 此时,我们可以看到程序正常退出了,原因是我们并没有对程序下断点,所以,跑起来后直接执行完毕
b [行号] 打断点
此时,再让程序跑起来 程序就会在下断点的这行停下来
逐过程调试(n )&& 逐语句调试(s )
n:逐过程,相当于F10,不会进入被调函数的内部 s逐语句:相当于F11,会跳转到函数的内部进行执行 具体看以下示例: 逐过程: 逐语句:
查看断点 (i b )
继续执行 c (continue)
删除断点
删除所有断点 delete breakpoints
删除某一个序号对应的断点 delete breakpoint 断点序号
1、对代码打两个断点
2、删除序号为3的断点
禁用断点 disable breakpoint
禁用断点 此时我们再让程序跑起来,断点就不会再将程序停止下来,程序会运行到底,直到代码跑完
启用断点 enable breakpoint
p [变量名] : 查看变量的值
现在查看number的值 我们发现number的值此时是0,由于堆number变量的初始化语句还没有执行,所以number此时存放的是未初始化值。 现通过调试命令,将 int number = 100 ;这条语句执行之后,再来查看变量number的值
当然,p也可以查其他类型的变量值,例如指针,结构体,结构体指针等等 比如
info locals :查看当前栈帧局部变量的值
此时可以看到,我们的函数停在第41行处,处于main函数的栈帧 此时,我们调用命令info locals 来查看当前栈帧的局部变量值 那么我们来看另外以一种情况 当代码执行到Swap函数内部停下来后栈帧内局部变量又是怎样呢? 我们先在代码的30行处下一个断点,随后逐语句调试,进入Swap函数内部 此时我们来查看函数栈帧的局部变量: 我们发现,该函数栈帧内的局部变量只有一个,temp。与我们的代码是相对应的。 说明:info locals 展示的一定是当前栈帧的局部变量
当前栈帧是什么意思? 我们知道,函数在被调用时,会在栈上为其开辟一块空间,该快空间就是该函数的栈帧
bt :展示调用的堆栈
可以通过调用堆栈来查看代码执行的函数调用关系 对于函数调用关系,应该从下往上看
等待Swap函数执行完毕后,再来查看堆栈的调用情况
此时,只有main函数一个存在,Swap函数对应的栈帧在Swap函数执完毕之后,已经被释放掉了!
q : 退出
当一个程序调试完成后,或者中途用户想要退出调试时,可以通过命令 q实现
调试的应用场景
1、程序还没执行起来,调试可执行程序 2、调试崩溃程序产生的coredump文件(本小节着重总结)
2.1 coredump文件:核心转储文件,是程序在崩溃的一瞬间内存的映像,相当于案发现场 2.2 ulimit -a core file size:决定产生的coredump文件最大能够多大 3.3调试命令 gdb 可执行程序 coredump文件
该行的最后一数字表示核心转储文件的大小
若为0:表示程序崩溃也不会产生coredump文件 unlimited:不限制核心转储文件的大小
如果程序崩溃了,理论上不管coredump文件多大,都会产生
“理论上”的含义:由硬盘的大小决定
- 若产生的coredump文件小于空闲的磁盘空间,那么可以产生
- 若产生的coredump文件大于空闲的磁盘空间,即使core file size的值为unlimited,那也不会生成coredump文件(磁盘空间不足)
那么我们现在现将coredump文件的大小设置为unlimited 现在,我们提供一个有错误的代码,让其执行后产生coredump文件,我们对其进行一定 的分析
#include<stdio.h>
2 void Print(int *data)
3 {
4 *data = 1;
5 printf("%d\n",*data);
6 }
7
8 int main()
9 {
10
11
12 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
13 printf("%d\n",arr[100]);
14
15 int number = 1000;
16 int *p = &number;
17 Print(p);
18 return 0;
19 }
示例1
编译执行后发现程序崩溃了 此时,查看当前目录下的文件 现在我们通过gdb 可执行程序 coredump文件 来查看发生错误的原因 注意:要想通过 gdb+coredump方式进行调试,可执行程序应该也是debug版本
对于该行代码进行分析: 首先它是一条输出语句,语法正确。那么问题肯定就在参数上
- 首先查看输出类型与参数类型是否匹配
- arr是否支持下标访问
- arr的下标是否合法
本题通过这样的思路方能确定错误源于:数组的越界访问 因此很容易就能根据出错原因修改代码
示例2
下面我将源码的部分内容改动如下 现在我们再来重新编译一下代码 重新执行发现,程序还是崩溃了 那么我们继续来找原因 很明显,原因是函数的参数并没有保存地址 所以对其解引用找不到一块内存空间来存放数据1
示例3
我们再对代码进行调整 对其编译并执行 此时,我们再来查看coredump文件
对于这种情况,我们首先找到是在哪里调用了这个函数,也就是找到该参数内的值的来源,找到后,根据程序代码的实际应用场景,来审查该值的合法性。最终确定问题根源所在。
对于coredump文件的分析在日后的编程学习过程中是尤为重要的,我们要熟练地使用gdb+coredump来调试我们的程序。
今天的总结就到此结束了,欢迎各位看官们留下痕迹~~
|