Linux操作系统学习:day08

内容来自:Linux介绍

视频推荐:Linux基础入门教程-linux命令-vim-gcc/g++ -动态库/静态库 -makefile-gdb调试

目录

day08

53、命令和编辑模式之间的切换

如果要编辑文件,需要从命令模式切换到文件编辑模式,切换模式的快捷键有很多,不同的快捷键对应的效果有所不同,效果如下表所示:

快捷键 功能
i 从光标前边开始输入
a 从光标的后边开始输入
o 在光标下边创建新行,在新行中输入
s 删除光标后边的字符(盖住的字符),从删除的字符位置开始输入
I (大写的i) 从当前行行首开始输入
A 从当前行行尾开始输入
O 在光标上边创建新行,在新行中输入
S 删除当前行,在当前行开始输入

文件编辑完成之后,从编辑模式回到命令模式只需要按键盘上的 Esc 即可。

54、命令模式到末行模式的切换与末行模式下的保存退出

命令模式到末行模式的切换

从命令模式切换到末行模式只需要在键盘上输入一个 :,同时这个符号也会出现在窗口的最下端,这时候我们就可以在最后一行输入我们执行的命令了。

shell 复制代码
# 命令模式切换到末行模式
在命令模式下键盘输入一个 冒号  -> :

# 从末行模式 -> 命令模式
1. 按两次esc
2. 在末行模式下执行一个完整指令, 执行完毕, 自动回到命令模式

从末行模式切换回命令模式有两种方式:

  1. 按两次 Esc
  2. 在末行模式下执行一个完整指令,执行完毕,自动回到命令模式
保存退出

使用 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用户都有效;
  • 如果两个配置文件都设置了, 用户级别的配置文件起作用(用户级别优先级高)。

轻松搞定Vim插件安装

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 个步骤合并成一个。 先介绍一个每个步骤都分别做了写什么事儿:

  1. 预处理:在这个阶段主要做了三件事: 展开头文件宏替换去掉注释行
    • 这个阶段需要GCC调用预处理器来完成, 最终得到的还是源文件, 文本格式
  2. 编译:这个阶段需要GCC调用编译器对文件进行编译, 最终得到一个汇编文件
  3. 汇编:这个阶段需要GCC调用汇编器对文件进行汇编, 最终得到一个二进制文件
  4. 链接:这个阶段需要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 加加的区别

关于对 gccg++ 很多人的理解都是比较片面的或者是对二者的理解有一些误区,下边从三个方面介绍一下二者的区别:

  1. 在代码编译阶段(第二个阶段):
    • 后缀为 .c 的,gcc 把它当作是C程序,而 g++ 当作是 C++ 程序
    • 后缀为.cpp 的,两者都会认为是 C++ 程序,C++ 的语法规则更加严谨一些
    • g++会调用gcc,对于C++代码,两者是等价的,也就是说 gcc 和 g++ 都可以编译 C/C++代码
  2. 在链接阶段(最后一个阶段):
    • gcc 和 g++ 都可以自动链接到标准C库
    • g++ 可以自动链接到标准C++库,gcc如果要链接到标准C++库需要加参数 -lstdc++
  3. 关于 __cplusplus 宏的定义
    • g++ 会自动定义__cplusplus 宏,但是这个不影响它去编译C程序
    • gcc 需要根据文件后缀判断是否需要定义 __cplusplus 宏 (规则参考第一条)

综上所述:

  1. 不管是 gcc 还是 g++ 都可以编译 C 程序,编译程序的规则和参数都相同
  2. g++可以直接编译C++程序, gcc 编译 C++程序需要添加额外参数 -lstdc++
  3. 不管是 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
相关推荐
落羽的落羽2 分钟前
【C++】二叉搜索树
开发语言·数据结构·c++·学习
西阳未落6 分钟前
Linux(12)——基础IO(下)
linux·运维·服务器
什么半岛铁盒8 分钟前
云服务器Xshell登录拒绝访问排查
运维·服务器
FINE!(正在努力!)8 分钟前
PyTest框架学习
学习·pytest
cido17 分钟前
kali在apt update报错提示没有公钥
linux·apt·kali
wqqqianqian1 小时前
国产linux系统(银河麒麟,统信uos)使用 PageOffice在线编辑word文件保存数据同时保存文件
linux·word·信创·国产·保存·pageoffice·在线编辑
国际云1 小时前
腾讯云国际版和国内版账户通用吗?一样吗?为什么?
大数据·运维·阿里云·云计算
心之语歌1 小时前
ubuntu24.04 搭建 java 环境服务,以及mysql数据库
linux·ubuntu
fengye2071611 小时前
板凳-------Mysql cookbook学习 (十)
学习·mysql·adb