内容来自:Linux介绍
视频推荐:Linux基础入门教程-linux命令-vim-gcc/g++ -动态库/静态库 -makefile-gdb调试
目录
-
- day08
-
- 53、命令和编辑模式之间的切换
- 54、命令模式到末行模式的切换与末行模式下的保存退出
- 55、末行模式下的替换操作
- 56、末行模式下的分屏操作
- 57、在末行模式下进行行的跳转和执行shell命令
- [58、vim 的配置文件](#58、vim 的配置文件)
- [59、gcc 的安装和版本查看](#59、gcc 的安装和版本查看)
-
- [安装 GCC](#安装 GCC)
- [60、gcc 的工作流程和多文件编译](#60、gcc 的工作流程和多文件编译)
- [61、gcc 参数简介和参数 (`-o`):指定生成的文件名使用举例](#61、gcc 参数简介和参数 (
-o
):指定生成的文件名使用举例) - [62、gcc 的 `-l`(大i)参数的使用举例](#62、gcc 的
-l
(大i)参数的使用举例) - [63、gcc 的 `-D` 参数的使用举例](#63、gcc 的
-D
参数的使用举例) - [64、gcc 和 g 加加的区别](#64、gcc 和 g 加加的区别)
day08
53、命令和编辑模式之间的切换
如果要编辑文件,需要从命令模式切换到文件编辑模式,切换模式的快捷键有很多,不同的快捷键对应的效果有所不同,效果如下表所示:
快捷键 | 功能 |
---|---|
i |
从光标前边开始输入 |
a |
从光标的后边开始输入 |
o |
在光标下边创建新行,在新行中输入 |
s |
删除光标后边的字符(盖住的字符),从删除的字符位置开始输入 |
I (大写的i) |
从当前行行首开始输入 |
A |
从当前行行尾开始输入 |
O |
在光标上边创建新行,在新行中输入 |
S |
删除当前行,在当前行开始输入 |
文件编辑完成之后,从编辑模式回到命令模式只需要按键盘上的
Esc
即可。
54、命令模式到末行模式的切换与末行模式下的保存退出
命令模式到末行模式的切换
从命令模式切换到末行模式只需要在键盘上输入一个
:
,同时这个符号也会出现在窗口的最下端,这时候我们就可以在最后一行输入我们执行的命令了。
shell
# 命令模式切换到末行模式
在命令模式下键盘输入一个 冒号 -> :
# 从末行模式 -> 命令模式
1. 按两次esc
2. 在末行模式下执行一个完整指令, 执行完毕, 自动回到命令模式
从末行模式切换回命令模式有两种方式:
- 按两次
Esc
- 在末行模式下执行一个完整指令,执行完毕,自动回到命令模式
保存退出
使用 vim 对文件编辑完成之后,需要保存或者退出 vim 一般都是在末行模式下完成的,不管是进行那种操作都有对应的操作命令,如下表:
末行模式下输入的命令 | 功能 |
---|---|
q |
退出, 如果退出的时候文件没有保存, vim会提示是否要保存 |
q! |
直接退出, 不保存 (强制退出) |
w |
保存, 不退出 (相当在windows中于按了ctrl+s) |
wq |
保存退出 |
x |
保存退出 |
55、末行模式下的替换操作
末行模式下的替换比命令模式下的替换功能要强大的多,在末行模式下可以指定将什么样的内容替换为什么样的内容,并且可以指定替换某一行或者某几行或者是全文替换。
替换对应的命令是
s
并且可以给其指定参数。默认情况下只替换相关行的第一个满足条件的关键字, 如果需要整行替换需要加参数/g
。
末行模式下的替换命令 | 说明 |
---|---|
s/被替换的关键字/新的关键字/g |
只对光标所在行进行替换 |
行号1, 行号2s/被替换的关键字/新的关键字/g |
[行号1 , 行号2] 是一个从小到大的范围, 对这个范围进行替换 |
%s/被替换的关键字/新的关键字/g |
% 代表对所有行进行替换 |
56、末行模式下的分屏操作
分屏就是将当前屏幕中的窗口以
水平
或者垂直
的方式拆分成多个, 在不同的子窗口中可以显示同一个文件或者不同文件中的内容,下边介绍一下相关的分屏命令:
末行模式命令或者快捷键 | 说明 | 备注 |
---|---|---|
sp |
水平分屏 , 多个窗口垂直排列 | 多个窗口中显示同一个文件里的内容 |
vsp |
垂直分屏, 多个窗口水平排列 | 多个窗口中显示同一个文件里的内容 |
ctrl+w+w |
光标在打开的屏幕之间切换 | 快捷键操作 (按住ctrl然后按两次w) |
qall |
同时退出多个屏幕 | |
wqall |
同时保存退出多个屏幕 | |
sp 文件名 |
分屏的同时指定打开的文件的名字 | 在新窗口中显示指定的文件的内容 |
vsp 文件名 |
分屏的同时指定打开的文件的名字 | 在新窗口中显示指定的文件的内容 |
除了在命令模式下分屏, 我们也可以在使用vim打开文件的时候直接分屏, 下边是需要用到的参数:
-o
: 水平分屏-O
: 垂直分屏
shell
# 在 vim 打开文件的时候指定打开多个文件和分屏方式
# 水平分屏
$ vim -o 文件1, 文件2, 文件3 ...
# 垂直分屏
$ vim -O 文件1, 文件2, 文件3 ...
57、在末行模式下进行行的跳转和执行shell命令
行跳转
在 vim 中不仅可以在命令模式下进行行的跳转,也可以在末行模式下进行行跳转,末行模式下指定哪一行光标就可以跳转到哪一行。
shell
:行号 # 输入完行号之后敲回车
执行shell命令
在使用 vim 编辑文件的过程中,还可以在末行模式下执行需要的shell命令,在执行 shell 命令之前需要在前边加上一个叹号
!
。
shell
# 语法:
:!shell命令
# 举例
:!ls # 回车即可
58、vim 的配置文件
vim 是一个文本编辑器工具,这个工具也是有配置文件的,文件的名字叫做
vimrc
,在里边可以设置样式
,功能
,快捷键
等属性 。对应的配置文件分为两种用户级别
和系统级别
。
- 用户级别的配置文件(
~/.vimrc
)只对当前用户有效; - 系统级别的配置文件(
/ect/vim/vimrc
)对所有Linux用户都有效; - 如果两个配置文件都设置了, 用户级别的配置文件起作用(用户级别优先级高)。
59、gcc 的安装和版本查看
GCC
是 Linux 下的编译工具集,是 GNU Compiler Collection
的缩写,包含 gcc、g++
等编译器。这个工具集不仅包含编译器,还包含其他工具集,例如 ar、nm 等。
GCC 工具集不仅能编译 C/C++语言,其他例如 Objective-C、Pascal、Fortran、Java、Ada 等语言均能进行编译。GCC 在可以根据不同的硬件平台进行编译,即能进行交叉编译,在 A 平台上编译 B 平台的程序,支持常见的 X86、ARM、PowerPC、mips 等,以及 Linux、Windows 等软件平台。
安装 GCC
有些纯净版的Linux默认没有gcc编译器, 需要自己安装, 在线安装步骤如下:
shell
# 安装软件必须要有管理员权限
# ubuntu
$ sudo apt update # 更新本地的软件下载列表, 得到最新的下载地址
$ sudo apt install gcc g++ # 通过下载列表中提供的地址下载安装包, 并安装
# centos
$ sudo yum update # 更新本地的软件下载列表, 得到最新的下载地址
$ sudo yum install gcc g++ # 通过下载列表中提供的地址下载安装包, 并安装
gcc安装完毕之后, 可以查看版本:
shell
# 查看 gcc 版本
$ gcc -v
$ gcc --version
# 查看 g++ 版本
$ g++ -v
$ g++ --version
60、gcc 的工作流程和多文件编译
gcc 的工作流程
GCC 编译器对程序的编译下图所示,分为 4 个阶段:
预处理(预编译)
、编译和优化
、汇编
和链接
。GCC 的编译器可以将这 4 个步骤合并成一个。 先介绍一个每个步骤都分别做了写什么事儿:
- 预处理:在这个阶段主要做了三件事:
展开头文件
、宏替换
、去掉注释行
- 这个阶段需要GCC调用预处理器来完成, 最终得到的还是源文件, 文本格式
- 编译:这个阶段需要GCC调用编译器对文件进行编译, 最终得到一个汇编文件
- 汇编:这个阶段需要GCC调用汇编器对文件进行汇编, 最终得到一个二进制文件
- 链接:这个阶段需要GCC调用链接器对程序需要调用的库进行链接, 最终得到一个可执行的二进制文件
文件名后缀 | 说明 | gcc 参数 |
---|---|---|
.c |
源文件 | 无 |
.i |
预处理后的 C 文件 | -E |
.s |
编译之后得到的汇编语言的源文件 | -S |
.o |
汇编后得到的二进制文件 | -c |
在 Linux 下使用 GCC 编译器编译单个文件十分简单,直接使用 gcc 命令后面加上要编译的 C 语言的源文件,GCC 会自动生成文件名为
a.out
的可执行文件(也可以通过参数 -o 指定生成的文件名
),也就是通过一个简单的命令上边提到的4个步骤就全部执行完毕了。但是如果想要单步执行也是没问题的,下边基于这段示例程序给大家演示一下。
c
// 假设程序对应的源文件名为 test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main()
{
int array[5] = {1,2,3,4,5};
for(int i=0; i<5; ++i)
{
printf("array[%d] = %d\n", i, array[i]);
}
return 0;
}
第一步: 对源文件进行预处理, 需要使用的gcc参数为
-E
shell
# 1. 预处理, -o 指定生成的文件名
$ gcc -E test.c -o test.i
第二步: 编译预处理之后的文件, 需要使用的gcc参数为
-S
shell
# 2. 编译, 得到汇编文件
$ gcc -S test.i -o test.s
第三步: 对得到的汇编文件进行汇编, 需要使用的gcc参数为
-c
shell
# 3. 汇编
$ gcc -c test.s -o test.o
第四步: 将得到的二进制文件和标准库进制链接, 得到可执行的二进制文件,
不需要任何参数
shell
# 4. 链接
$ gcc test.o -o test
最后再次强调, 在使用gcc编译程序的时候可以通过参数控制内部自动执行几个步骤:
shell
# 参数 -c 是进行文件的汇编, 汇编之前的两步会自动执行
$ gcc test.c -c -o app.o
# 该命令是直接进行链接生成可执行程序, 链接之前的三步会自动执行
$ gcc test.c -o app
tips:生成c文件的可执行程序用gcc,生成cpp文件的可执行程序用g++。
多文件编译
GCC 可以自动编译链接多个文件,不管是目标文件还是源文件,都可以使用同一个命令编译到一个可执行文件中。
1、准备工作
首先将程序编译之前需要的代码准备出来,例如一个项目包含3个文件,文件 string.h,string.c 中有一个函数 strLength 用于计算字符串的长度,而在 main.c 中调用这个函数将计算的结果显示出来。
-
头文件
c#ifndef _STRING_H_ #define _STRING_H_ int strLength(char *string); #endif // _STRING_H_
-
源文件 string.c
c#include "string.h" int strLength(char *string) { int len = 0; while(*string++ != '\0') // 当*string 的值为'\0'时, 停止计算 { len++; } return len; // 返回字符串长度 }
-
源文件 main.c
c#include <stdio.h> #include "string.h" int main(void) { char *src = "Hello, I'am Monkey·D·Luffy!!!"; printf("string length is: %d\n", strLength(src)); return 0; }
2、编译运行
因为头文件是包含在源文件中的,因此在使用gcc编译程序的时候不需要指定头文件的名字(
在头文件无法被找到的时候需要使用参数 -I 指定其具体路径而不是名字
)。我们可以通过一个 gcc 命令将多个源文件编译并生成可执行程序,也可以分多步完成这个操作。
-
直接链接生成可执行程序
shell# 直接生成可执行程序 test $ gcc -o test string.c main.c # 运行可执行程序 $ ./test
-
先将源文件编成目标文件,然后进行链接得到可执行程序
shell# 汇编生成二进制目标文件, 指定了 -c 参数之后, 源文件会自动生成 string.o 和 main.o $ gcc --c string.c main.c # 链接目标文件, 生成可执行程序 test $ gcc --o test string.o main.o # 运行可执行程序 $ ./test
61、gcc 参数简介和参数 (-o
):指定生成的文件名使用举例
下面的表格中列出了常用的一些
gcc
参数,这些参数在 gcc命令中没有位置要求
,只需要编译程序的时候将需要的参数指定出来即可。
gcc编译选项 | 选项的意义 |
---|---|
-E | 预处理指定的源文件,不进行编译 |
-S | 编译指定的源文件,但是不进行汇编 |
-c |
编译、汇编指定的源文件,但是不进行链接 |
-o [file1] [file2] / [file2] -o [file1] |
将文件 file2 编译成文件 file1 |
-I directory (大写的i) |
指定 include 包含文件的搜索目录 |
-g |
在编译的时候,生成调试信息,该程序可以被调试器调试 |
-D | 在程序编译的时候,指定一个宏 |
-w | 不生成任何警告信息, 不建议使用, 有些时候警告就是错误 |
-Wall | 生成所有警告信息 |
-On | n的取值范围:0~3。编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高 |
-l |
在程序编译的时候,指定使用的库 |
-L |
指定编译的时候,搜索的库的路径。 |
-fPIC/fpic |
生成与位置无关的代码 |
-shared |
生成共享目标文件。通常用在建立共享库时 |
-std |
指定C方言,如:-std=c99,gcc默认的方言是GNU C |
指定生成的文件名 (-o)
该参数用于指定原文件通过 gcc 处理之后生成的新文件的名字,有两种写法,原文件可以写在参数
-o
前边后缀写在后边。
shell
# 参数 -o 的用法,原材料 test.c 最终生成的文件名为 app
# test.c 写在 -o 之前
$ gcc test.c -o app
# test.c 写在 -o 之后
$ gcc -o app test.c
62、gcc 的 -l
(大i)参数的使用举例
如果在程序中包含了一些头文件,但是包含的一些头文件在程序预处理的时候因为找不到无法被展开,导致程序编译失败,这时候我们可以在gcc命令中添加
-I
参数重新指定要引用的头文件路径, 保证编译顺利完成。
shell
# -I, 指定头文件目录
$ tree
.
├── add.c
├── div.c
├── include
│ └── head.h
├── main.c
├── mult.c
└── sub.c
# 编译当前目录中的所有源文件,得到可执行程序
$ gcc *.c -o calc
main.c:2:18: fatal error: head.h: No such file or directory
compilation terminated.
sub.c:2:18: fatal error: head.h: No such file or directory
compilation terminated.
通过编译得到的错误信息可以知道,
源文件中包含的头文件无法被找到
。通过提供的目录结构可以得知头文件head.h 在 include 目录中
,因此可以在编译的时候重新指定头文件位置,具体操作如下:
shell
# 可以在编译的时候重新指定头文件位置 -I 头文件目录
$ gcc *.c -o calc -I ./include
63、gcc 的 -D
参数的使用举例
在程序中我们可以使用宏定义一个常量,也可以通过宏控制某段代码是否能够被执行。在下面这段程序中第8行判断是否定义了一个叫做
DEBUG
的宏,如果没有定义第9行代码就不会被执行了,通过阅读代码能够知道这个宏是没有在程序中被定义的。
c
// test.c
#include <stdio.h>
#define NUMBER 3
int main()
{
int a = 10;
#ifdef DEBUG
printf("我是一个程序猿, 我不会爬树...\n");
#endif
for(int i=0; i<NUMBER; ++i)
{
printf("hello, GCC!!!\n");
}
return 0;
}
如果不想在程序中定义这个宏,但是又想让它存在,通过gcc的参数
-D
就可以实现了,编译器会认为参数后边指定的宏在程序中是存在的。
shell
# 在编译命令中定义这个 DEBUG 宏,
$ gcc test.c -o app -D DEBUG
# 执行生成的程序,可以看到程序第9行的输出
$ ./app
我是一个程序猿, 我不会爬树...
hello, GCC!!!
hello, GCC!!!
hello, GCC!!!
-D 参数的应用场景:
在发布程序的时候,一般都会要求将程序中所有的log输出去掉, 如果不去掉会影响程序的执行效率,很显然删除这些打印log的源代码是一件很麻烦的事情,解决方案是这样的:
将所有的打印log的代码都写到一个宏判定中, 可以模仿上边的例子
在编译程序的时候指定 -D 就会有log输出
在编译程序的时候不指定 -D,log就不会输出
64、gcc 和 g 加加的区别
关于对
gcc
和g++
很多人的理解都是比较片面的或者是对二者的理解有一些误区,下边从三个方面介绍一下二者的区别:
- 在代码编译阶段(第二个阶段):
- 后缀为
.c
的,gcc 把它当作是C程序,而 g++ 当作是 C++ 程序 - 后缀为
.cpp
的,两者都会认为是 C++ 程序,C++ 的语法规则更加严谨一些 - g++会调用gcc,对于C++代码,两者是等价的,也就是说 gcc 和 g++ 都可以编译 C/C++代码
- 后缀为
- 在链接阶段(最后一个阶段):
- gcc 和 g++ 都可以自动链接到标准C库
- g++ 可以自动链接到标准C++库,gcc如果要链接到标准C++库需要加参数
-lstdc++
- 关于
__cplusplus
宏的定义- g++ 会自动定义
__cplusplus
宏,但是这个不影响它去编译C程序 - gcc 需要根据文件后缀判断是否需要定义
__cplusplus
宏 (规则参考第一条)
- g++ 会自动定义
综上所述:
- 不管是 gcc 还是 g++ 都可以编译 C 程序,编译程序的规则和参数都相同
- g++可以直接编译C++程序, gcc 编译 C++程序需要添加额外参数
-lstdc++
- 不管是 gcc 还是 g++ 都可以定义
__cplusplus
宏
# 编译 c 程序
$ gcc test.c -o test # 使用gcc
$ g++ test.c -o test # 使用g++
# 编译 c++ 程序
$ g++ test.cpp -o test # 使用g++
$ gcc test.cpp -lstdc++ -o test # 使用gcc