一、vim:一个多模式编辑器(有命令模式、输入模式、底行模式)
1、三种模式的切换
2、不同模式下的操作方式:
w、b:光标按照单词进行行内跨行进行移动
j、k、l:左下上右
(n)yy:复制光标所在行
(n)dd:剪切删除
(n)p粘贴(n重复行)到光标所在行下一行
u:撤销
ctrl+r:撤销之前的撤销
命令模式下:
gg:定位光标到最开始行
shift+g(G):定位光标到最结尾行
n+shift+g(nG):定位光标到任意行定位光标到当前行结尾
shift+$:定位光标到当前行开始
shift+^:定位光标到当前行结尾
shift+~:大小写转换
(n)r:对光标字符和之后的所有字符进行批量化替换
shift+r(R):替换模式对内容进行整体替换(第四种模式)
(n)x:对光标字符之后的字符进行删除
ctrl+ww:多文件切换(光标)
多文件时操作时,底行中vs打开多个文件编辑窗口,窗口光标切换,光标在哪一个窗口里面,就对哪一个窗口进行操作
w、b:光标按照单词进行行内跨行进行移动
j、k、l:左下上右
(n)yy:复制光标所在行
(n)dd:剪切删除
(n)p粘贴(n重复行)到光标所在行下一行
u:撤销
ctrl+r:撤销之前的撤销
批量化注释:命令模式ctrlv,左下角弹出v-block,按hjkl,选中区域,shift i,//,esc
批量化去注释:命令模式ctrlv,左下角弹出v-block,按hjkl,选中区域,shift i,x,esc
vim /etc/sudoers
root的身份进行sudo
userdel -r 用户名:删除用户
二、编译文件(gcc/g++):
程序翻译的过程:
1、预处理
a.去注释
b.头文件展开
c.条件编译
d.宏替换
-E:进行程序的编译,直至将预处理工作做完
2、编译(生成汇编)
-S:进行程序的翻译,直至将编译工作做完
3、汇编(生成机器可识别代码)
-c:进行程序的翻译,直至将汇编工作做完
4、链接(生成可执行文件或库文件)
xxx.o:可重定位目标二进制文件,简称目标文件,obj文件。虽然已经是二进制,但不可以独立执行,需要经过链接才能执行。
将可重定位目标。二进制文件和库进行链接,形成可执行程序
三、动态库与静态库
1、下载动静态库
sudo yum install -y glibc-static
sudo yum install -y libstbc++-static
2、在Linux中,编译形成可执行程序,默认采用的就是动态链接--提供动态库。
3、在Linux中,如果按照静态链接的方式形成可执行程序,需要添加static选项,提供静态库。
4、gcc默认形成的可执行程序是以release方式发布的
-g:以debug方式进行软件发布。(形成可执行程序的时候添加了debug信息,可以被追踪调试)
四、make与makefile
1、make是一条指令,makefile当前目录下的一个文件
2、依赖关系、依赖方法
Makefile注释用#
Make会自动退到makefile中的依赖关系栈式结构
Make会自顶向下扫描makefile,形成的第一个目标文件充当为Make的默认动作
3、问:为什么重复编译不通过?答:提供编译效率!
问:怎么做到的?
答:原理如下:
一定是源文件形成可执行,现有源文件,才有可执行。一般而言,原文件的最近修改时间比可执行成文件要老!如果我们修改了原文件,历史上曾经还有可执行,那么原文件的最近修改时间,一定要比可执行程序要新!
只需要比较,可执行程序的最近修改时间和源文件的最近修改时间:.exe新于.c源文件,不需要重新编译,.exe老于.c源文件,需要重新编译。
4、Access(最后一次访问时间)、Modify(最后一次被修改时间)与Change(权限最后一次修改时间)
文件=文件内容(Modify)+文件属性(Change)
touch后面如果跟已存在文件,则将所有时间(access、modify、change)更新为最新
touch -a 文件名:更新Access
touch -m 文件名:更新Modify
touch -c 文件名:更新Change
总结:make会根据源文件和目标文件的新旧判定是否需要重新执行依赖关系进行编译。
若需要总是执行的呢?
5、.PHONY(伪目标):mycode依赖关系,依赖方法总是被执行
编译效果:
特殊符号:
$@:目标文件
$^:依赖文件
@:不回显依赖方法
编译效果:
学了以上内容,就让我们写一个进度条程序巩固以上知识吧
//processBar.h
#pragma once
#include <stdio.h>
#define NUM 102
#define TOP 100
#define BODY '='
#define RIGHT '>'
extern void processbar(int rate);
extern void initbar();
//processBar.c
#include "processBar.h"
#include <string.h>
#include <unistd.h>
const char *lable="|/-\\";
char bar[NUM];
#define GREEN "\033[0;32;32m"
#define NONE "\033[m"
void processbar(int rate)
{
if(rate < 0 || rate > 100) return;
int len = strlen(lable);
printf(GREEN"[%-100s]"NONE"[%d%%][%c]\r", bar, rate, lable[rate%len]); // 没有\n,就没有立即刷新,因为显示器模式是行刷新
fflush(stdout);
bar[rate++] = BODY;
if(rate < 100) bar[rate] = RIGHT;
}
void initbar()
{
memset(bar, '\0', sizeof(bar));
}
//main.c
#include "processBar.h"
#include<unistd.h>
typedef void (*callback_t)(int);//函数指针类型
//模拟一种安装或者下载
void download(callback_t cb)
{
int total = 1000;//1000MB
int curr = 0;//0Mb
while(curr <= total)
{
usleep(50000);//模拟下载花费的时间
int rate = curr*100/total;//更新进度
cb(rate);//通过回调,展示进度
curr += 10;
}
printf("\n");
}
int main()
{
printf("download 1: \n");
download(processbar);
initbar();
printf("download 2: \n");
download(processbar);
initbar();
printf("download 3: \n");
download(processbar);
initbar();
printf("download 4: \n");
download(processbar);
initbar();
return 0;
}
#Makefile
processbar:processBar.c main.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f processbar
五、Linux调试器:gdb的使用
readelf -S 文件名:读取可执行程序二进制构成的文件debug
在Makefile文件中chang常在依赖关系后加后缀-g,让可执行程序以debug方式发布。
以debug方式发布的可执行程序具有调试信息。
以debug方式发布的可执行程序比以默认(release)方式发布的可执行程序略大(多了调试信息)。
gdb+可执行程序名:进入调试模式
调试模式中的常用指令:
l+行数:查看从l行开始的部分代码(连续回车能继续显示未显示代码)
l+函数名:查看某函数
r:运行程序
quit:退出
b+行号:打断点
b+文件名:行号:在某文件指定行打断点
b+文件名:行号:打断点
b+函数名:打断点至函数首行
b+文件名:函数名:打断点至函数首行
info b:查看断点信息
d+编号:删断点
r:运行至断点(相当于VS的F5)
n:逐过程(相当于VS的F10)
s:逐语句(相当于VS的F11)
p+监视目标:监视
display+监视目标:常显示监视
undisplay+监视目标编号:取消常显示监视
until+行数:跳转运行至指定的行
finish:跑完函数
c:跳转运行至下一个断点
disable+断点编号:禁用断点(非删除)
enable+断点编号:取消禁用断点(非删除)
set var:修改变量的值
bt:查看各级函数调用及参数