文章目录
vim编辑器的三种模式
用vim编辑器打开一个文本,默认是命令模式,想对文本输入内容
1.敲一个i进入插入模式
2.想回到命令模式,Esc返回
3.从命令模式进入底行模式,输入一个冒号,回到命令模式同理
底行模式和插入模式不能直接转换
vim命令模式的一些常用操作
yy,复制当前文本行,nyy从光标处开始向下复制n行文本
p,粘贴到光标的下一行,np重复粘贴n次
dd:剪切,ndd从光标处开始向下剪切n行文本
shift + 4,将光标移动到当前文本行的末尾
shift + 6,将光标移动到当前文本行的开始
shift + g,移动到文本的末尾
gg,移动到文本的开头
u,撤销操作
ctrl+ r,撤销上一次u的操作
n + shift + g移动到文本的第n行
r,替换当前字符
shift + r,类似insert,批量化替换
shift + ~,大小写转换
w,b,当前行的后移,前移,以单词为单位的移动
h,j,k,l,左下上右
编译过程的感性认知
一段文本要转换成机器能看懂的语言要经过翻译和链接两步,其中翻译又细分为三个部分:预处理,编译,汇编,这些过程都做了什么?
1.预处理:宏替换,头文件展开,去注释,条件编译(将代码变得干净)
2.编译:将干净的代码转换成汇编代码
3.汇编:将汇编代码转换成机器能看懂的可重定位的二进制代码
4.链接:链接代码中调用的库
用代码解释编译过程
用gcc直接编译这个test.c文件会直接生成一个可执行程序
-o指定生成文件的名字
-E选项,只执行编译的第一步:预处理,预处理后的文件通常用i作为后缀。
在底行输入vs test.c,可以同时看两个文件,使用ctrl+w+w,光标在两个分屏窗口切换
可以看到头文件被展开,宏替换,去注释,条件编译后生成的预处理文件
-S选项,对i文件进行编译生成汇编代码,文件通常以s作为后缀。
s文件中都是汇编代码
-c选项,对s文件进行汇编,生成机器能看懂的二进制文件
od -x xxx,xxx是文件名,这是查看二进制文件的指令。编译后的一部分代码就如上图所示。
此时的test.o还不能执行(连执行属性都没有),强行加上后又说不能执行该二进制文件。原因是生成可执行程序还差最后一步:链接,代码中包含了头文件。头文件只是声明了有这个方法可以使用,但这个方法的具体实现在库中(可以将库理解为特殊处理过的源文件),链接就是将库与代码产生联系(链接起来)
使用gcc直接对文件进行操作,gcc指令中默认会将文件与库进行链接,此时的out文件就是可执行文件
动态库与静态库概念
动态库后缀 Linux(.so) windows(.dll)
静态库后缀 Linux(.a) windows(.lib)
由动态库与静态库引出的两个概念:动态链接和静态链接,动态库作为单独文件独立于你的代码文件存在,如果你的代码需要调用动态库,程序会找到动态库的存储位置然后调用里面的函数,一般情况下动态链接较为常见。
而静态链接是将静态库拷贝到你的代码文件中,如果调用的静态库较多,拷贝的代价会很大,你的文件大小也随之增加
(安装c语言静态库:sudo yum install -y glibc-static,安装c++静态库:sudo yum install -y libstdc++ -static)
静态链接产生的文件大小大概是动态的100倍
gdb的使用
用gcc默认编译的文件版本是release的,release版本不能进行调试,在gcc命令后加上-g选项,编译的版本就是debug,能进行调试的版本。
test_g.out比test.out多出了一千多字节,这些多出的信息就是文件的调试信息。
调试的相关指令
进入gdb,gdb 文件名(test_g.out),文件必须是-g选项生成的可执行文件
- b(break) 行号,打断点
- info b,查看所有断点信息
- d 断点编号,删除断点
- l 行号,显示该行的代码
- s(step),逐语句,(可以进入函数)
- n(next),逐过程,(跳过函数)
- display && undisplay,常显示一个变量的值和取消常显示
- until 行号,跳转到指定行
- r,运行程序
- c(continue),从一个断点运行到另一个断点
- finish,执行完一个函数就停止
- quit,退出
(l 0很好用,连续敲回车可以依次查看代码)
makefile/make
(make是一个命令,makefile是一个文件)
vs作为一个集成开发环境,可以不用对每个源文件进行编译,vs会自动编译工程中所有的源文件(ctrl + B自动编译),但linux中的工程,如果源文件的数量较多,在该工程中应该先编译哪个源文件?整个工程的结构应该是怎样的?使用Linux的编译器就会面临这样的问题,Linux提供了一个工具makefile,该工具能解决整个工程的编译问题。
makefile的目的是编译文件,要达到这个目的需要告知源文件和可执行文件之间的依赖关系,以及源文件生成可执行文件的依赖方法。
所以makefile中要写依赖关系和依赖方法,比如test.out依赖test.c生成,要生成这个可执行文件的依赖方法是gcc test.c -o test.out,
第一行的依赖关系,test.out依赖test.c生成,
- 格式为目标文件:依赖文件
第一行就是test.out:test.c,第二行要先敲一个Tab,接着是编译该可执行文件的指令,比如gcc test.c -o test.out。
PHONY是一个关键字,.PHONY:后跟一个伪目标,也就是说使用make命令后,系统不会生成这个目标文件,因为它是伪目标,声明完伪目标后,由于clean **“文件”**没有依赖文件,所以clean的冒号后为空,定义完目标文件clean后,回车Tab写上删除文件的指令。(rm -f删除文件,如果文件不存在不输出提示信息)
要删除生成的可执行文件就敲make clean命令
被.PHONY修饰的伪目标,表示该依赖关系总是被执行,何为总是被执行?无论目标文件是否新旧,直接执行依赖关系
clean是.PHONY修饰的伪目标,用make clean执行依赖关系:rm -f test.out时,由于系统不会伪目标,所以系统执行make clean时,检测到makefile的同级目录下没有该目标文件,所以总是指向伪目标的依赖方法。而make生成的目标文件test.out没有被.PHONY修饰,make生成了目标文件后,再次make,系统检测到test.out是新生成的文件,并且其依赖文件的没有更新,所以不会执行gcc test.c -o test.out这个依赖关系。
还有一点,make只会生成第一个目标文件,执行该依赖关系的依赖方法。如果clean写在test可执行文件前面,make就只会clean
最后,可以用$@, $^简化书写
- $@表示目标文件, $^表示依赖文件
- 如果依赖文件不止一个,那么$^表示所有的依赖文件
test.out:test.c
gcc $@ -o $^
可以用这两个符号写makefile文件
目标文件的新旧,系统是怎样分别的?
通过时间来区别文件的新旧,Linux中的文件由内容和属性组成,使用stat命令显示文件的状态信息,可以看到文件有三个时间
- Access:文件的访问时间,如果进入该文件达到一定的次数这个时间会更新
- Modify:文件的内容被修改,时间更新
- Change:文件的属性被修改,时间更新
但修改了文件的内容,Modify时间一定改变,而修改内容可能改变文件的属性,所以Change时间也可能改变
比如test.c生成目标文件test.out,那么test.c的修改时间一定先于test.out,但修改了test.c,test.c的修改时间就会改变。使用make命令时,如果test.c的修改时间后于目标文件test.out,那么make会执行依赖关系gcc test.c -o test.out,如果依赖的修改时间先于目标文件,那么make不会指向依赖关系
makefile的多文件使用
解析一下makefile的逻辑:现在有两个源文件hello.c和main.c,将这两个源文件编译成hello.o和main.o目标文件后,将这两个目标文件作为新的目标文件hello的依赖文件进行编译
clean:清理目标文件,将所有以.o结尾的文件清理,以及hello这个可执行文件
缓冲区理解
这段代码是先输出hello world再休眠还是先休眠在输出hello world?由于缓冲区的存在,程序的结果是先睡眠再输出。因为缓存区是一段内存,缓冲区采用的刷新策略是行刷新,当缓冲区没有满或者一行没有结束时,缓冲区的内容不会向显示器输出。如果在hello world后加上\n,就会先打印hello world,再睡眠。
进度条的打印
进度条运行的效果
%-100s,打印字符串,预留100个字符的空间,-的意思是让打印内容从左向右填充。
后面是一个旋转的特效,依次定义plan中的每个字符,为了保证不越界,cnt要%4。
plan中要用\表示\,因为\是一个转义字符。
但这段代码最重要的一部分是fflush(stdout),将缓存区的内存向标准输出流中输出,也就是输出到屏幕,每次进度条变化都要刷新缓冲区,否则这个效果就会一卡一卡的(但同样的代码在vs下,不加fflush却不会造成卡顿,这说明vs和gcc的缓冲区刷新机制不同,vs是直接输出,gcc则是达到缓冲区满了再输出)。
git使用
用git clone xxx将远程仓库克隆到本地,xxx是仓库的网址。用git上传代码的三板斧:git add xxx,xxx是文件名,add之后git commit -m “xxx”,xxx是这次提交的日志,,最后是git push,将提交的代码上传到远程仓库里。
当仓库的代码需要更新时,使用git pull拉取最新的代码。
git status,查看这次提交的文件
.gitignodre文件里存储的是git提交可以忽略的文件后缀,即带有该后缀的文件不会被上传,是一个黑名单文件。