
目录
[1 Linux下安装软件的常见方式](#1 Linux下安装软件的常见方式)
[2 Linux中 Vim 编辑器的使用](#2 Linux中 Vim 编辑器的使用)
[2.1 命令模式:](#2.1 命令模式:)
[2.2 插入模式:](#2.2 插入模式:)
[2.3 底行模式:](#2.3 底行模式:)
[3 Linux 编译器 gcc/g++的使用](#3 Linux 编译器 gcc/g++的使用)
[3.1 GCC 编译过程](#3.1 GCC 编译过程)
[4 Linux 项目自动化构建工具-make/Makefile](#4 Linux 项目自动化构建工具-make/Makefile)
[5 Linux小程序--进度条实现:](#5 Linux小程序--进度条实现:)
[5.1 前置小知识](#5.1 前置小知识)
[5.2 进度条实现](#5.2 进度条实现)
[6 Linux调试器-gdb使用](#6 Linux调试器-gdb使用)
[6.1 启动与退出调试](#6.1 启动与退出调试)
[6.2 查看源码](#6.2 查看源码)
[6.3 打断点](#6.3 打断点)
[6.4 查看所有断点](#6.4 查看所有断点)
[6.5 删除断点](#6.5 删除断点)
[6.6 禁用断点](#6.6 禁用断点)
[6.7 断点运行与调试](#6.7 断点运行与调试)
[6.8 变量监视](#6.8 变量监视)
[6.9 高级调试技巧](#6.9 高级调试技巧)
1 Linux下安装软件的常见方式
1.源代码安装
-
rpm包安装
-
包管理器安装(推荐)
例如:手机上的应用商店就相当于 包管理器安装
2 Linux中 Vim 编辑器的使用

常用:
2.1 命令模式:
n + yy : 复制当前行 , n表示连续复制n行
n + p : 粘贴,当前光标的下一行,n表示把指定的内容粘贴n次
u : 撤销当前操作
ctlr+ r : 对历史u撤销进行撤销恢复
n + dd : 剪切/删除指定行,连续的多行
n + x : 删除光标后面的字符
n + X : 删除光标之前的字符
n + r + '字符 ': 表示对光标指定的位置,进行字符的替换,也可以替换多个
shift + r = R : 替换模式,直接进行文本替换
shift + ` = ~ : 大小写快速切换
shift+4 = $ : 把光标定位到 行的最结尾
shift+6 = ^ : 把光标移动到 行的最开头
n + gg : 把光标定位到文本的最开始, n表示定位到文本的第几行
shift + g = G :把光标定位到文本的最结尾
h , j k,l : 表示上下左右移动也可以带n
h: 表示光标往左移动
l : 光标往右移动
j : 光标往下移动
k : 光标往上移动
w : 表示按照单词为单位进行光标后移动
b : 表示按照单词为单位进行光标前移动
代码注释:
注释多行
① ctrl + v : 进入试图模式,h,j,k,l 进行区域选择

② shift + i = I 进入插入模式 输入//
③ esc 两次即可完成注释

取消注释:进入视图模式,区域选择,选中// ,d 即可去注释
2.2 插入模式:
a,i,o : 进入插入模式
2.3 底行模式:
set nu : 显示行号
set nonu : 不显示行号
s/原词/要替换的词/g
/关键字 : 搜索关键字
vs test.c 开启分屏窗口
ctrl + ww : 移动光标到另一个分屏窗口
vim 编辑器配置,cd ~ 后,vim .vimrc 中可以配置vim编辑器
3 Linux 编译器 gcc/g++的使用
3.1 GCC 编译过程
gcc 如何完成?
3.1.1 预处理:主要包括宏定义、去注释、文件包含、条件编译(动态代码裁剪)
预处理指令是以#号开头的代码行
示例:gcc -E hello.c -o hello.i
-E 指的是让gcc在预处理结束后停止编译过程
-o 指的是目标文件,.i文件表示已经过预处理的C原始程序

这里值得注意的是条件编译:
示例1:调试开关
cpp
#include <stdio.h>
#define DEBUG // 如果这行有定义,则编译调试代码;如果注释掉,则不编译
int main() {
int x = 10;
#ifdef DEBUG
printf("Debug: x = %d\n", x); // 只有DEBUG被定义时才编译
#endif
printf("Program running...\n"); // 总是编译
return 0;
}
示例2:防止头文件重复包含
cpp
// my_header.h
#ifndef MY_HEADER_H // 如果没定义MY_HEADER_H
#define MY_HEADER_H // 就定义它
// ... 头文件的内容(函数声明、类定义等)
#endif // MY_HEADER_H // 结束条件编译
3.1.2 编译:检查代码的规范性以及是否有语法错误等,检查无误后把代码翻译成汇编语言。
示例:gcc -S hello.i -o hello.s
-S表示指进行编译不进行汇编,生成汇编代码(hello.s)

3.1.3 汇编:把编译完成的汇编文件汇编成目标文件
示例:gcc -c hello.s -o hello.o
-c表示汇编代码转化为.o的二进制目标代码

3.1.4 连接: 将各个独立的 .o 目标文件以及系统库文件(静态库或动态库)合并到一起。
主要工作是符号解析 和地址重定位,把未确定的函数调用地址填补正确,最终生成可执行文件。
示例:gcc hello.o -o hello

./可执行程序,./hello

链接库查询:ldd code.exe

我们经过预处理、编译、汇编和连接这一系列操作过于繁琐,所以接下来的自动化构建工具就能够帮助我们提高效率。
4 Linux 项目自动化构建工具-make/Makefile
make是一个命令,makefile是一个文件
makefile/make会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法
简单例子:
vim makefile 进入:

gcc前面必须是 Tab 缩进,不能空格,否则 Makefile 报错。
使用例子:

自动推导:我们可以在makefile文件写入编译方法


这样写太繁琐了,下面方法比较方便:(推荐)


makefile也是支持变量的,使用变量:$(变量名) 或者 ${变量名}
例如,bin和src都是变量名
$@ 代表目标 (target) ,也就是冒号左边的那一项。 这里目标是 code.exe,所以 $@ = code.exe
$^ 代表所有依赖文件 ,冒号右边全部依赖。 这里依赖是code.c,所以$^ = code.c
等价于:gcc -o code.exe code.c
这里我们发现每次make的时候都会出现命令的打印,这里隐藏命令的方法是:
@放到依赖方法的前面,@依赖方法,例如:
例1:

运行结果:

例2:
可以适当接入一些提示输出echo等,依赖方法可以执行多行的
bash
bin=code.exe
src=code.c
$(bin):$(src)
@gcc -o $@ $^
@echo "compiler $(src) to $(bin) ..."
@echo "Compilation complete!"
@echo "Run the program with ./code.exe"
.PHONY:clean
clean:
@rm -f $(bin)
@echo "clean project files ..."
运行结果:

5 Linux小程序--进度条实现:
5.1 前置小知识
5.1.1 关于回车
回车和换行:
'\n' 指的就是回车和换行两个动作
'\r'回车是到行头
下面: 有\n的是先打印然后再sleep 3秒

没有\n的是先sleep 3秒,然后再打印

这里涉及到缓冲区,缓冲区可以简单理解成一个块内存空间,程序结束时,一般要进行自动刷新缓冲区,'\n' 是进行刷新缓冲区(行刷新)
5.1.2 关于fflush
这里我们想要让光标一直回到刚开始的位置,例如就像倒计时打印,想要数字原地倒计时,就是让数字显示一下刷新一下(将缓冲区的数据强制刷新到屏幕)
值得注意的是:
这里倒计时打印,目前实现了回车,但是数字没有打印,这是因为C语言标准库中stdout输出默认是行缓冲模式,也就是说只有当遇到 '\n' 、强制刷新或者缓冲区满的时候才把内容输出到文件。(从Linux一切皆是文件的角度分析,也就是把内容强制写入到负责屏幕输出的文件里面)

所以这里的解决方法是使用强制刷新
fflush
通过man 手册查看fflush
man fflush

所以我们给加上:
cpp
fflush(stdout);

所以接下来直接进行使用底行模式进行运行程序:
在命令模式下,使用感叹号!调用系统命令来运行程序。

运行结果:

接下来实现进度条:
5.2 进度条实现
简单版:
使用一个存储101个字符的字符串用来存放'#',然后刷新并打印每次存放的字符串的情况
cpp
#define Len 101
#define Style '#'
void TestBar()
{
int n = 0;
char Bar[Len];
memset(Bar,'\0',sizeof(Bar));
while(n <= 100 )
{
Bar[n] = Style;
printf("[%-100s][%3d%%]\r",Bar,n);
++n;
fflush(stdout);
usleep(100000);
}
printf("\n");
}
运行结果:

关于美化:可以100% 后面加入旋转的lable,| / - \
cpp
#include"ProcessBar.h"
#define Len 101
#define Style '#'
void TestBar()
{
int n = 0;
char Bar[Len];
memset(Bar,'\0',sizeof(Bar));
const char* lable = "|/-\\";
while(n <= 100 )
{
Bar[n] = Style;
printf("[%-100s][%3d%%] [%c]\r",Bar,n,lable[n%4]);
++n;
fflush(stdout);
usleep(100000);
}
printf("\n");
}

复杂版:
接下来我可能有这样的需求,当在多个文件的场景下,每个文件都有进度条

多个文件都有进度条
cpp
#include "ProcessBar.h"
#define Style '#'
#define Len 101
const char* lable = "|/-\\";
void ProcBar(double total,double current)
{
char Bar[Len];
memset(Bar,'\0',sizeof(Bar));
int len = strlen(lable);
//compute the current rate
double rate = (100.0*current)/total;
int loop_count = (int)rate;
int n = 0;
while(n <= loop_count)
{
Bar[n++] = Style;
}
Print the download progress based on the amount of data downloaded each time
fflush(stdout);
usleep(100000);
}

优化:
彩色进度条
可以适当给printf加上打印的颜色
cpp
printf("\033[32m[%-100s]\033[0m \033[33m%6.1lf%%\033[0m %c\r",Bar,rate,lable[n%len]);

6 Linux调试器-gdb使用
在linux命令行里面进行调试,通常可以使用gdb进行调试,平时使用的 gcc -o test test.c 指的编译程序一般编译的是release模式下,但是我们需要进行程序的调试,所以需要去编译debug模式下的程序。
一般情况下,编译器形成可执行程序的时候,会调试信息,在gcc/g++让debug模式编译 -g
bash
gcc -o test-debug test.c -g
我们发现debug的可执行程序的文件的大小确实比release模式下大

同时也可以 把可执行程序的符号表读出,这里可以把debug信息筛选出
bash
readelf -S test-debug | grep debug

6.1 启动与退出调试
gdb 可执行程序 进入调试,按q可以退出
注意这里的可行程序是debug模式下的

6.2 查看源码
gdb下查看文件内容
list 文件名:行号

6.3 打断点
调试程序跑起来需要先打断点,再run
打断点,可以使用b 文件名:行号/函数名


6.4 查看所有断点
我们知道在VS里面都会有红色的断点显示
在gdb中使用info b用来显示当前打的断点 (打断点的意思就是在调试程序的某个地方停下来)

6.5 删除断点
删除断点需要参考info b 列表前面的编号
d 断点编号

6.6 禁用断点
与删除断点不同,当我们打完断点后,我们像保留这个位置的断点,但是又不想先去直接使用这
个断点,所以说像给禁用一下 :disable 断点编号,使能断点由y变成n

我又想使能之前禁用的断点
enable 禁用的断点编号

6.7 断点运行与调试
运行调试程序
打完断点后 run即可
我们还知道调试可以 逐过程和逐语句,gdb逐过程输入n(next)

gdb逐语句输入s(step)

6.8 变量监视
gdb 查看监视窗口的变量
p 变量内容/地址

监视多个变量
display 变量

取消某个常显示变量
undisplay 常显示的编号

6.9 高级调试技巧
c(continue)运行到下一个断点处

当我们进入某函数里面进行调试,函数循环,我们想进行逐函数执行
finish 完成所在函数的执行

until 行号 : 跳转到指定行,中间代码都是运行完成的

info local :查看函数中的临时变量的值

set var :修改变量的值

bt: 查看当前栈帧局部变量的值

