云服务器vim配置和指令,gcc和make的使用

vim

1、VS是集成开发环境,所有功能集于一体。

在linux中拆分为1、编辑器 vim;2、编译器 gcc; 3、调试器 gdb

2、vi 就是简单版的vim,vim就是增强版的vi

配置vim

基本配置

本质是将我们的配置项放入.vimrc文件中

[yyq@localhost 2022_09_26_lesson5]$ cd ~ #回到用户的家目录
[yyq@localhost ~]$ touch .vimrc 
[yyq@localhost ~]$ vim .vimrc
[yyq@localhost ~]$ cat .vimrc
set nu
-----------以上是最简单的,下面记录课堂给的(针对云服务器的配置)------------
[yyq@localhost ~]$ curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
[yyq@localhost ~]$ source ~/.bashrc

插件配置

vim的多种模式

修改vim主题配色 :colorscheme+空格+Tab

任何模式切换,都可以先esc切换到命令模式,再去别的模式。

1、命令模式(默认模式)esc

当一个文件所处的命令模式时,输入的任何内容都被当作命令了。

控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。

shift+4 #定位行尾(行左)
shift+6 #定位行开头(行右)
# 上述称为 锚点
##################
shift+g #定位文件末尾
g+g #定位文件开头
数字shift+g #定位到第 数字 行
b #光标按单词进行前移
w #光标按单词进行后移
h #光标一个一个地左移
j #光标一个一个地下移
k #光标一个一个地上移
l #光标一个一个地右移
##################
yy #复制光标所在行
p #粘贴
yy p #复制1次
number p #粘贴number次
number yy #复制从当前行开始的number行
number yy number p #批量拷贝
u #撤销操作
ctrl+r #取消u操作
dd #剪切光标所在行
number dd #剪切从当前行开始的number行
x #删除光标所在的位置之后一个字符
number x #批量化删除字符
shift+x #删除光标所在的位置之前一个字符
number shift+x #批量化删除字符
shift+r #替换光标所在的一个字符
number shift+r #批量化替换
cw #更改光标所在处的字到字尾处
cnumberw #如c3w表示更改3个词
###########################
shift+~ #大小写转换
vs xxx.c #vim同时打开2个文件窗口
ctrl+w+w #在两个窗口间切换

2、插入模式a/i/o

只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。

a #光标后移

i #光标位置不变

o #光标新起一行

s #光标删除一个字符

3、底行模式:

文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。

在命令模式下,shift+: 即可进入该模式。要查看你的所有模式:打开vim,底行模式直接输入

:set nu #设置行号
:wq #保存并退出
:w! #强制保存
########################
:vs filename #文件夹下有这个文件,就会分屏打开,没有就会新建再打开
########################
:!命令 #执行linux命令
:!gcc file.name #不关闭窗口直接编译
:!man 3 function #直接查function的描述
:%s/printf/cout/g #s是替换,把printf替换成cout,g是global的意思

gcc/g++

安装gcc和g++

sudo yum install -y gcc-c++

程序编译过程

1、预处理(进行宏替换) -E

头文件展开、去注释、宏替换、条件编译

处理之后还是c语言

gcc –E hello.c –o hello.i #预处理后,将临时内容写入hello.i文件

2、编译(生成汇编) -S

把c语言变成汇编语言

gcc –S hello.i –o hello.s
gcc –S hello.c –o hello.s

3、汇编(生成机器可识别代码)-c

.o称为目标可重定向文件,是二进制文件,不可执行。因为printf是库函数,我们需要把第三方库链接进来才能变成可执行程序。

gcc –c hello.s –o hello.o #把汇报语言变成目标可重定向文件
gcc –c hello.c –o hello.o

od test.o #以8进制的形式查看二进制文件
od以8进制的形式查看二进制文件

4、连接(生成可执行文件或库文件)

gcc会根据文件类型(后缀),引入我们在代码中所使用的第三方库,比如c库。这个链接是由编译器和文件类型共同决定的。比如写test.cpp就会链接到cpp的库。

gcc hello.o –o hello #把目标可重定向文件变成可执行文件
gcc hello.c –o hello

ldd hello #查看链接的库
[yyq@localhost 2022_09_26_lesson5]$ ldd hello
	linux-vdso.so.1 =>  (0x00007ffc5cbfe000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f2bbae40000) #这里是关键,libc,c是c库。libc.so.6是动态链接库。libc.a是静态库。库真正的名字去掉lib,去掉.xxxx,libc.so.6就是c
	/lib64/ld-linux-x86-64.so.2 (0x00007f2bbb20e000)

动态库.so 静态库.a

在linux下库的命名:动态库:libxxx.so,静态库:libxxxx.a,去掉前缀,去掉.a/.c后缀,剩下的就是库的名称。

Linux下默认形成可执行程序,默认使用的是动态库,如libc-2.17.so。

[yyq@VM-8-13-centos ~]$ ls /lib64/libc.so.6 -l
lrwxrwxrwx 1 root root 12 Jul 25 16:58 /lib64/libc.so.6 -> libc-2.17.so
[yyq@VM-8-13-centos ~]$ ls /lib64/libc-2.17.so -l
-rwxr-xr-x 1 root root 2156592 May 19  2022 /lib64/libc-2.17.so

libc.so.6是动态链接库,属于弱连接。libc.a是静态库,属于强连接。

[yyq@VM-8-13-centos ~]$ gcc test.c -o test.exe
[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ file test.exe
test.exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=581edf32039ef04f8b42db07c90975d4c1ae1517, not stripped
//dynamically linked (uses shared libs)可以看出是动态链接的
[yyq@VM-8-13-centos ~]$ gcc test.c -o test.s.exe -static //不知道为啥我的虚拟机上运行不了这个代码,报错
#报错如下
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

解决方法(网上找的能用,在lib64下面也会有libc.a这个库,实际上下载了是在/usr/lib64/libc.a下,如果lib64找不到的话可以cp libc.a /usr/lib64/libc.a

#查看libc.a是否已经安装
sudo find / -name 'libc.a'
#centos系列安装
sudo yum install -y glibc-static

同理c++的静态库安装命令为

sudo yum install -y libstdc++-static

安装完成以后,使用file和ldd

file查看文件动/静态链接 ldd查看可执行文件的动态链接库

[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ gcc test.c -o test_static -static
[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ file test_static
test_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=a7cd36e27f10320e5bf6844e6e22a935212330bd, not stripped
//statically linked可以看出是静态链接的
[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ ldd test.exe
	linux-vdso.so.1 =>  (0x00007ffd097f1000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fcefccdc000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fcefd0aa000)
//.c编译生成的可执行文件 动态链接库有3个
[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ ldd test_static
	not a dynamic executable
//.c编译生成的可执行文件 使用静态库编译的可执行文件就无法查看动态链接库
[yyq@VM-8-13-centos 2022_11_27_BasicTool]$ ldd mytest
	linux-vdso.so.1 =>  (0x00007ffdf9ffb000)
	libstdc++.so.6 => /home/yyq/.VimForCpp/vim/bundle/YCM.so/el7.x86_64/libstdc++.so.6 (0x00007f22563cb000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f22560c9000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f2255eb3000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f2255ae5000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f225674c000)
//.cpp编译生成的可执行文件 有6个动态链接库

一般而言,系统会自动携带动态库,静态库需要自己安装。为什么呢?因为一般而言,系统运行要用的是动态链接库。

系统本身为了支持我们编程,给我们提供了标准库的.h(告诉我们怎么用),标准的动静态库.so/.a(告诉我们,它有方法实现)。

我们的程序+库的代码==可执行程序。

make/makefile

make是一条命令,makefile是一个文件

多个文件怎么编到一起呢?

1、将多文件统一先编译成.o文件,再将*o统一链接生成.exe文件

gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc -c test3.c -o test3.o
#然后
gcc test1.o test2.o test3.o -o test.exe

#实例
[yyq@localhost mk]$ ll
total 12
-rw-rw-r--. 1 yyq yyq  56 Sep 27 10:13 main.c
-rw-rw-r--. 1 yyq yyq 106 Sep 27 10:12 mytest.c
-rw-rw-r--. 1 yyq yyq  84 Sep 27 10:09 mytest.h
[yyq@localhost mk]$ gcc mytest.c main.c -o mybin  #将2个c文件直接编译
[yyq@localhost mk]$ ll
total 24
-rw-rw-r--. 1 yyq yyq   56 Sep 27 10:13 main.c
-rwxrwxr-x. 1 yyq yyq 8424 Sep 27 10:16 mybin
-rw-rw-r--. 1 yyq yyq  106 Sep 27 10:12 mytest.c
-rw-rw-r--. 1 yyq yyq   84 Sep 27 10:09 mytest.h

2、当文件有很多很多的时候,要用Linux项目自动化构建工具-make/Makefile

# 1、先在当前目录下 创建一个文件 Makefile或者makefile
[yyq@localhost mk]$ touch Makefile #此处用大写打头
[yyq@localhost mk]$ ll
total 12
-rw-rw-r--. 1 yyq yyq  56 Sep 27 10:13 main.c
-rw-rw-r--. 1 yyq yyq   0 Sep 27 10:19 Makefile
-rw-rw-r--. 1 yyq yyq 106 Sep 27 10:12 mytest.c
-rw-rw-r--. 1 yyq yyq  84 Sep 27 10:09 mytest.h
# 2、打开Makefile或者makefile 文件,写入
mybin:mytest.c main.c  #要生成的文件名:依赖于那些文件
	gcc main.c mytest.c -o mybin

.PHONY:clean
clean:
	rm -f mybin #要删除的文件名
还可以这么写,把依赖关系反过来写也可以!先-E,再-S,再-c,再输出可执行文件
mybin:mytest.o
	gcc mybin.o -o mybin
mybin.o:
	gcc -c mybin.s -o mybin.o
mybin.s:mybin.i
	gcc -S mybin.i -o mybin.s
mybin.i:mytest.c
	gcc -E mybin.c -o mybin.i
	
.PHONY:clean
clean:
	rm -f mybin.i mybin.s mybin.o mybin #要删除的文件名
##执行的时候是倒序的,因为根据依赖关系会自动寻找。因为执行第一条命令时,需要mybin.o,但没有,就会往下找mybin.s->mybin.i->mybin.c,所以就会先执行-E,再执行-S,再执行-c,最后执行-o。

# 3、执行make命令,生成可执行文件
[yyq@localhost mk]$ make #也可以写为make mybin
gcc main.c mytest.c -o mybin
[yyq@localhost mk]$ ./mybin
hello:0 hello:1 hello:2 hello:3 hello:4 hello:5 hello:6 hello:7 hello:8
# 4、执行make clean命令,清理可执行文件
[yyq@localhost mk]$ make clean

深度剖析Makefile文件

makefile有1、依赖关系;2、依赖方法。通常情况下缺一不可。

mybin:mytest.c main.c #依赖关系 mybin依赖于mytest.c main.c
	gcc main.c mytest.c -o mybin #tab+依赖方法

.PHONY:clean # PHONY是makefile的关键字,用这个修饰的叫做伪目标
clean:
	rm -f mybin #依赖方法

前提是依赖方法没有改变的情况下:伪目标(make clean)总是被执行的,而(make)第一行目标文件只能执行一次。总是被执行指的是依赖关系是否可以无障碍执行。

make会扫描Makefile文件的第一个命令,就去执行。(make mybin == make),而clean是第二个命令,所以要用make clean。

**为什么gcc知道这个文件是最新的呢(make只能执行一次)?**联系到 文件属性的三个时间stat filename,modify是指文件内容修改的时间,change是指文件属性(文件权限、文件大小等)被修改的时间,access是访问文件的时间(访问了不会立刻修改时间)。【在文件操作的时候,改文件次数多?还是访问文件的次数多?----当然是访问文件次数多,所以访问时间access的时间被更改的频率太高了,就会进行更多次的IO,即访问磁盘。实际上,我们也不在意访问时间,故设计者采用了一个策略:等访问次数到了一个值,才会更新access时间。】

第一次执行make时,.c文件的modify时间一定要比.exe文件的modify时间早,因为先有.c文件才有可执行文件;

第二次执行make时,.c文件的modify时间一定要比.exe文件的modify时间晚,才能说明.c被修改过,所以可执行文件也要更新,才能执行make命令。如果不存在时间差,执行make的时候,提示如下make: 'filename' is up to date.,就说明可执行文件已经是最新的了。

所以gcc是依靠 .c和可执行文件(就是依赖关系的这些文件)的modify的时间差来判断。

#####################

故用.PHONY修饰的伪目标实际上就是让make不要根据modify时间差来判断。

//如果改为下面这个代码
.PHONY:mybin ####修改
mybin:mytest.c main.c #依赖关系 mybin依赖于mytest.c main.c
	gcc main.c mytest.c -o mybin #tab+依赖方法

.PHONY:clean # PHONY是makefile的关键字,用这个修饰的叫做伪目标
clean:
	rm -f mybin #依赖方法
//make就能一直被执行,make clean也一直能被执行

在依赖方法前加上@符号,就可以让语句只执行不输出

mybin:main.o mytest.o
	gcc $^ -o $@
main.o:main.c
	gcc -c main.c
mytest.o:mytest.c
	gcc -c mytest.c

.PHONY:clean
clean:
	rm -f main.o mytest.o mybin 

------简化------
mybin:main.o mytest.o
	gcc $^ -o $@
%.o:%.c
	gcc -c $<
	
.PHONY:clean
clean:
	rm -f *.o mybin
# $^表示所有的依赖文件(依赖文件列表) $@表示目标文件
# %c表示当前目录下所有的.c文件,文件名展开 %.o表示对应的.c文件所形成的.o文件
# $<表示 把%.c所代表的源文件一个一个打出来,用gcc进行编译,形成同名.o文件
---------------------
%.o:%.c
	gcc -c $<
#相当于展开变成
main.o:main.c #%.o:%.c
	gcc -c main.c #$<
mytest.o:mytest.c #%.o:%.c
	gcc -c mytest.c #$<
----------------------

实例:进度条

1、缓冲区

#include <stdio.h>
#include <unistd.h>
//1
int main()
{
	printf("hello progress bar\n");
	sleep(3);//单位是秒
	return 0;
}
---------------------------------
//2
int main()
{
	printf("hello progress bar");
	sleep(3);
	return 0;
}

以上两段代码,仅仅是少了个\n的区别。

anyway程序就是自上而下的执行,这个没错!!但是为什么我们看到的是1会先执行printf再sleep,而2先sleep,那printf呢?

答:在缓冲区里面!缓冲区可以先理解为是一块内存区域,那就存在何时刷新的问题,目前的刷新策略又分为:无缓冲(立即刷新)、行缓冲(碰到\n就会把之前的数据一起刷新)、全缓冲(缓冲区很大,只有缓冲区满了才刷新)、程序退出(自动刷新)。很明显缓冲区的刷新策略是行缓冲

程序会先把printf中的数据读入到缓冲区里,遇到\n才刷新,而程序2没遇到\n,只能是程序退出时才刷新。

那我不想用\n,也想让缓冲区立刻刷新应该怎么做呢?用fflush

#include "ProgBar.h"

int main()
{
        printf("hello Progress Bar!");
        fflush(stdout);
        sleep(3);
        return 0;
}

2、\r \n

  • Unix系统里,每行结尾只有“<换行>”,即“\n”;
  • Windows系统里面,每行结尾是“<换行><回车>”,即“\n\r”;
  • Mac系统里,每行结尾是“<回车>”。

Windows:

​ ‘\r’ 回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;

​ ‘\n’ 换行,换到当前位置的下一行,而不会回到行首;

\n //换行,换行+回车,把光标先移到下一行,然后换到行首->也就是下一行的行首 
\r //回车,return 回到本行行首,这就会把这一行以前的输出覆盖掉,具体内部细节就像是输出缓冲区重新开始缓冲了一样

Unix系统:

​ 每行结尾只有“<换行>”,即"\n";

Linux:

​ 遇到换行符(‘\n’)会进行回车+换行的操作,回车符反而只会作为控制字符(‘^M’)显示,不发生回车的操作。

当我们采用如下代码时

#include "ProgBar.h"

int main()
{
	//1 正常显示
    int i = 3;
    while(i > 0)
    {
        printf("%d\n", i);
        sleep(1);
    	i--;
    }
    
    //2 正常显示 与\n效果相同
    int i = 3;
    while(i > 0)
    {
        printf("%d\r\n", i);
        sleep(1);
    	i--;
    }
    
    //3 无法显示
    int i = 3;
    while(i > 0)
    {
        printf("%d\r", i);
        sleep(1);
    	i--;
    }
        
    printf("hello Progress Bar!");
    fflush(stdout);
    sleep(3);
    return 0;
}
//结果
//1
	3
	2
	1
	hello Progress Bar!
//2
	3
	2
	1
	hello Progress Bar!
//3
	hello Progress Bar!

代码3不会显示任何数字,因为缓冲区是行刷新。要在后面加上fflush(stdout)就好了,只不过是覆盖刷新,3会变成2,再变成1,像倒计时一样。

//3   //2   //1
//hello Progress Bar!

代码3就是我们要用到的进度条设计

//ProgBar.h
  1 #pragma once
  2 
  3 #include <unistd.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6                                                                                                                 
  7 #define NUM 101
  8 
  9 void progress_bar();

 
//main.c
  1 #include "ProgBar.h"
  2 
  3 int main()         
  4 {
  5     progress_bar();
  6                                    
  7     //printf("hello Progress Bar!");
  8     //fflush(stdout);           
  9     //sleep(3);
 10     //printf("\n");
 11     return 0;                     
 12 }

//ProgBar.c
  1 #include "ProgBar.h"
  2 
  3 void progress_bar()
  4 {
  5     char bar[NUM];
  6     memset(bar, '\0', sizeof(bar));
  7 
  8     const char* label = "|/-\\";
  9     int i = 0;
 10     while(i <= 100)
 11     {
 12         printf("[%-100s][%-3d%%][%c]\r", bar, i, label[i%4]);
 13         fflush(stdout);
 14         bar[i++] = '#';
 15         usleep(50000);                                                                                          
 16     }
 17     printf("\n");
 18 }
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值