系统编程之vim-gcc-动态库静态库-makefile-GDB调试

编辑器gedit介绍

gedit是一个GNOME桌面环境下兼容UTF-8的文本编辑器。它使用GTK+编写而成,因此它十分的简单易用,有良好的语法高亮,对中文支持很好,支持包括gb2312、gbk在内的多种字符编码。gedit是一个自由软件。

这是 Linux 下的一个纯文本编辑器,但你也可以把它用来当成是一个集成开发环境 (IDE), 它会根据不同的语言高亮显现关键字和标识符。

gedit是一个Linux环境下的文本编辑器,类似windows下的写字板程序,在不需要特别复杂的编程环境下,作为基本的文本编辑器比较合适。
简单理解就是一个文本编辑器,类似于nodepad++这种软件。
在这里插入图片描述

什么是vi(vim)

vi (Visual interface)编辑器是 Linux 系统中最常用的文本编辑器,vi 在Linux界有编辑器之神的美誉,几乎所有的 Linux 发行版中都包含 vi 程序。

vi 工作在字符模式下,不需要图形界面,非常适合远程及嵌入式工作,是效率很高的文本编辑器,尽管在 Linux 上也有很多图形界面的编辑器可用,但vi的功能是那些图形编辑器所无法比拟的。

vim 是 vi 的升级版,它不仅兼容 vi 的所有指令,而且还有一些新的特性,例如 vim 可以撤消无限次、支持关键词自动完成、可以用不同的颜色来高亮你的代码。vim 普遍被推崇为类 vi 编辑器中最好的一个。

vim工作模式

  • 三种模式的切换图:

在这里插入图片描述

命令行模式
  • 在shell编辑器中,输vim 文件名,进入该模式
  • 在该模式下一切输入的命令都会当作命令来执行
编辑模式
  • 在命令模式下输入i,a…等命令进入编辑模式
  • 进入编辑模式就可以管理自己的文件内容
末行模式
  • 在编辑模式下,按Esc键退出到命令行模式输入:,进入末行模式
  • 之后按wq,q,q!等命令退回到shell界面

vim教程

vim基本操作

  • vim 文件名,进入命令模式,之后按i,进入编辑模式,完成编辑后,按Esc键,退到末行模式,之后输入:,执行wq,q,q!等命令退回到shell界面

vim实用操作

命令行模式下的操作
  • 常用代码
按键功能
gg=G格式化代码
  • 切到编辑模式
按键功能
i光标位置当前处插入文字
I光标所在行首插入文字
o(字母)光标下一行插入文字(新行)
O(字母)光标上一行插入文字(新行)
a光标位置右边插入文字
A光标所在行尾插入文字
s删除光标后边的字符,从光标当前位置插入
S删除光标所在当前行,从行首插入
  • 光标移动
按键功能
Ctrl+f向前滚动一个屏幕
Ctrl+b向后滚动一个屏幕
gg到文件第一行行首
G到文件最后一行行首
mG或mgg到指定行,m为目标行数
0(数字)光标移到到行首(第一个字符的位置)
$光标移到到行位
l(小写L)向右移动光标
h想左移动光标
k向上移动光标
j向下移动光标
^光标移到到行首(第一个有效字符位置)
  • 复制粘贴
按键功能
[n]yy复制从当前行开始的n行
p把粘贴板上的内容插入到当前行
  • 删除
按键功能
[n]x删除光标后n个字符
[n]X删除光标前n个字符
D删除光标所在开始到此行结尾的字符
[n]dd删除从当前行开始的n行(准确来说,是剪切,剪切不粘贴即为删除)
dG删除光标所在开始到文件尾的所有字符
dw删除光标开始位置的字,包含光标所在字符
d0(0位数字)删除光标前本行所有内容,不包含光标所在字符
dgg删除光标所在开始到文件行首第一个字符开始的所有字符
  • 撤销恢复
按键功能
.(点)执行上一次操作
u撤销前一个命令
Ctrl+r反撤销
100+.执行上一次操作100次
  • 保存退出
按键功能
ZZ(shift+z+z)保存退出
  • 查找
按键功能
/字符串从当前光标位置向下查找(n,N查找内容切换)
?/字符串从当前光标位置向上查找(n,N查找内容切换)
  • 替换
按键功能
r替换当前字符
R替换当前行光标后的字符(按Esc退出替换模式)
  • 可视模式
按键功能
v按字符移动,选中文本,可配合h,j,k,l选择内容,使用d删除,使用y复制
shift+v行选(以行为单位)选中文本,可配合h,j,k,l选择内容,使用d删除,使用y复制
Ctrl+v列选 选中文本,可配合h,j,k,l选择内容,使用d删除,使用y复制
末行模式下的操作
  • 保存退出
按键功能
:wq保存退出
:x保存退出
:w filename保存到指定文件
:q退出,如果文件修改但没有保存,会提示无法退出
:q!退出,不保存

all代表所有
举例:
wqall:表示全部保存退出
qall:表示全部不保存退出

  • 替换
按键功能
: s/abc/123/光标所在行的第一个abc替换为123
: s/abc/123/g光标所在行的所有abc替换为123
:1,10s/abc/123/g将第一行至第10行之间的abc全部替换成123
:%s/abc/123/g当前文件的所有abc替换为123
:%s/abc/123/gc同上,但是每次替换需要用户确认
:1,$s/abc/123/g当前文件的所有abc替换为123
  • 分屏
按键功能
:sp当前文件水平分屏
:vsp当前文件垂直分屏
: sp 文件名当前文件和另一个文件水平分屏
: vsp 文件名当前文件和另一个文件垂直分屏
ctrl+w+w在多个窗口切换光标
:wall/:wqall/:qall保存/保存退出/退出所有分屏窗口
vim -O a.c b.c垂直分屏
vim -o a.c b.c水平分屏
  • 其他用法扩展
按键功能
:!man 3 printf在vim中执行命令 (q退出)
:r !ls -l将ls -l执行的结果写入当前文件中
:r /etc/passwd将/etc/passwd文件中的内容写入到当前文件中
:w /tmp/txt将当前文件内容写入到/tmp/txt文件中
:w! /tmp/txt强制将当前文件内容写入到/tmp/txt文件中
:1,10s/^g将第1行到10行行首添加// (^表示行首) //\转移字符
:1,10s#^#//#g将第1行到10行行首添加// (#可以临时代替/ 分隔)
:%s/;/\r{\r\treturn0;\r}\r/g将;替换成{ return 0; }
:1,10s#//##g将第1行到10行行首去掉// (#可以临时代替/ 分隔)
  • vim的配置
    • 系统配置
      • 配置文件:/etc/vim/vimrc 从网上搜索一个vim配置文件替换此文件,按自己的需求配置
        1. 会在每次启动vim工具时生效,作用于整个Linux系统,所有用户
        2. 内容:一系列的 末行命令
    • 用户配置
      • 配置文件:~/.vimrc 该文件不存在,需要手动创建
        1. 会在每次启动vim时,自动生效,作用于当前用户
        2. 内容:一系列的 末行命令

GCC编译器简介

编辑器(如vi、记事本)是指我用它来写程序的(编辑代码),而我们写的代码语句,电脑是不懂的,我们需要把它转成电脑能懂的语句,编译器就是这样的转化工具。就是说,我们用编辑器编写程序,由编译器编译后才可以运行!

编译器是将易于编写、阅读和维护的高级计算机语言翻译为计算机能解读、运行的低级机器语言的程序。

gcc(GNU Compiler Collection,GNU 编译器套件),是由 GNU 开发的编程语言编译器。gcc原本作为GNU操作系统的官方编译器,现已被大多数类Unix操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,gcc同样适用于微软的Windows。

gcc最初用于编译C语言,随着项目的发展gcc已经成为了能够编译C、C++、Java、Ada、fortran、Object C、Object C++、Go语言的编译器大家族。

# 编译命令格式:

gcc [options] file...

g++ [options] file...

说明:

  • 命令、选项和源文件之间使用空格分隔
  • 一行命令中可以有零个、一个或多个选项
  • 文件名可以包含文件的绝对路径,也可以使用相对路径
  • 如果命令中不包含输出可执行文件的文件名,可执行文件的文件名会自动生成一个默认名,Linux平台为a.out,Windows平台为a.exe

GCC工作流程和常用选项

  • gcc编译器从拿到一个c源文件到生成一个可执行程序,中间一共经历了4个步骤:
    在这里插入图片描述
1.预处理:
	- 将 源文件,展开 头文件、替换宏(变量宏、函数宏)、替换空行、空格、table
	- gcc -E hello.c -o hello.i
		* -E:预处理选项
		* -o:重命名
2.编译:编译器
	- 逐行检查程序中出现的 语法和词法错误!简单的逻辑错误。 -- 所有编译过程中,最耗时
	- gcc -S hello.i -o hello.s
		* -S:编译选项,如果编译无误,生成.s汇编文件
3.汇编:汇编器
	- 将.s汇编文件中,所有汇编指令,翻译成二进制机器码
	- gcc -c hello.s -o hello.o
		* -c:汇编选项。无错误检查。机器翻译。
4.链接:连接器
	- 将.o的目标文件,链接库文件、数据段合并、地址回填。生成可执行文件。
	- gcc hello.c -o hello
		* 此过程无专用参数。-o不是连接过程必须使用的参数。
  • 4个步骤并不是gcc独立完成的,而是在内部调用其他工具,从而完成的整个工作流程:

在这里插入图片描述gcc工作流程

# 创建并编辑hello.c文件
wjg@wjg:~$ vim hello.c
# 查看hello.c文件是否创建好
wjg@wjg:~$ ls hello.c
hello.c
# 第一步:进行预处理
wjg@wjg:~$ gcc -E hello.c -o hello.i
# 第二步:生成汇编文件
wjg@wjg:~$ gcc -S hello.i -o hello.s
# 第三步:生成目标代码
wjg@wjg:~$ gcc -c hello.s -o hello.o
# 第四步:生成可执行文件
wjg@wjg:~$ gcc hello.c -o hello
# 第五步:执行
wjg@wjg:~$ ./hello
hello,xiaowang
  • 常用: 直接将源文件生成一个可以执行文件
wjg@wjg:~$ gcc hello.c -o hello1
wjg@wjg:~$ ./hello1
hello,xiaowang
  • 如果不指定输出文件名字, gcc编译器会生成一个默认的可以执行a.out
wjg@wjg:~$ gcc hello.c
wjg@wjg:~$ ./a.out
hello,xiaowang

gcc常用选项

选项作用
-S(大写)只进行预处理和编译
-o file指定生成的输出文件名为file
-E只进行预处理
-c(小写)只进行预处理、编译和汇编
-v / --version查看gcc版本号
-g包含调试信息
-On n=0~3编译优化,n越大优化得越多
-Wall提示更多警告信息
-D编译时定义宏
  • 显示所有警告信息
wjg@wjg:~$ gcc -Wall a.c
  • 将警告信息当作错误处理
wjg@wjg:~$ gcc -Wall -Werror a.c
  • 测试程序(-D选项):test.c
  #include <stdio.h>
	int main(void)
	{
		printf("SIZE:%d\n",SIZE);
		return 0;
	}
wjg@wjg:~$ gcc test.c -DSIZE=10
wjg@wjg:~$ ./a.out
SIZE:10

静态库和动态库

函数库

  • 本质:一组函数。具有相近的功能或操作同一数据结构。
    • <string.h>:strcpy/strcmp/strcat/strlen/strstr/strchr/strtok…
    • 自定义库:<mysort.h>:bubble_sort/select_sort/qucik_sort/insert_sort…
  • 作用:
    • 代码复用
    • 程序积累
  • 发布形式:
    • 源码形式:
      • 优点:方便使用者学习和使用。
      • 缺点:1.保密性差。2.编译程序耗时。3.编译受平台、版本限制。
    • 二进制形式:
      • 优点、缺点,与上述相反
  • 我们使用的函数库:标准C库:/lib/x86_64-linux-gnu/libc.so.6

静态库

简述

  • 机制: 在编译程序时,复制静态库的代码片,到可执行程序中。
  • 优点:将函数库中的函数本地化。寻址方便,速度快。(库函数执行效率==自定义函数执行效率)
  • 缺点:消耗系统资源大,每个使用静态库的程序,都要复制一份,静态库。浪费内存。
  • 使用场景:多用于核心程序,保证时效性,可以忽略空间。
    制作
  1. 生成*.o目标文件。
gcc add.c sub.c mul.c -c   
#得到add.o sub.o mul.o
  1. 制作静态库
ar rcs lib静态库名.a add.o sub.o mul.o
	# ar:制作静态库的工具。gcc不具备制作静态库的功能
	# r:更新。c:创建(可省)。s:建立索引。
	# 静态库名:必须lib开头,以.a为后缀名。 - 使用file lib静态库名.a查看
  1. 使用静态库
gcc ./src/hello.c -o app -L ./lib -l mymath -I ./inc
# -L:表示要连接的库所在目录
# -I./: I(大写i) 表示指定头文件的目录为当前目录
#-l(小写L):指定链接时需要的库,去掉前缀和后缀
  1. 查看静态库
file 文件名
file libmymath.a
# 查看信息如下:
libmymath.a: current ar archive

动态库(共享库)

简介

  • 机制:代码共享
  • 优点:节省内存(共享)、易于更新(动态链接)
  • 缺点:相对于静态库而言,函数调用速度慢(函数地址"延时绑定")
  • 使用场景:
    1. 对程序执行的速度要求不是强烈,而对系统资源有一定要求的场景。
    2. 对于更新比较频繁程序。
      1. 停止运行程序
      2. 使用新库覆盖旧库(保证新库、旧库名称一致。接口一致。)
      3. 重启程序

重点强调

  1. 动态库是否加载到内存,取决于"程序是否运行"。
  2. 动态库加载至内存位置,不固定。

制作

  1. 生成与位置无关的 目标文件(*.o文件)
gcc -fPCI -c add.c sub.c mul.c
  1. 制作动态库
gcc -shared -o lib动态库名字.so add.o sub.o mlu.o
  1. 测试用静态库
gcc hello.c -o app1 -L ./lib -l mymath -I ./inc
  1. 查看静态库
file 文件名
# 例如
file libmymath.so
# 查看信息如下:
libmymath.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=41bf6a05764c5811c69e232d3e68ad17068b5b18, not stripped

  1. 启动 程序./app—>报错:
# 报错信息如下:
./app1: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
  • 错误原因:"动态链接器"ld-linux-x86-64.so.2搜索动态库的路径没有指定
    • 链接器:工作在gcc编译4过程中的"链接阶段"。工作结束,生成可执行文件
    • 动态链接器:工作于可执行程序运行之后,辅助加载器负责将动态库加载到内存
  • 查看错误:

在这里插入图片描述
6. 解决上述错误。–基本思想:给 动态链接器指定动态库路径

  • 环境变量法:
# 将当前动态库所在目录,加入到环境变量中
# 失效时间:终端一旦退出,环境变量的修改无效
export LD_LIBRARY_PATH:./lib
  • 配置文件法:将上述修改的环境变量的指令,写入到.bashrc中,每次启动的时候都会自动生效
# 打开bashrc文件
vim bashrc
# 配置如下命令:
export LD_LIBRARY_PATH=LD_LIBRARY_PATH:./lib
# 重新启动.bashrc文件
. .bashrc 或者 source .bashrc
  • 常用:缓存文件法,通过修改配置文件,修改缓存文件,生成动态库链接器需要搜寻的目录位置。
# 打开配置文件
sudo vim /etc/ld.so.conf
# 修改配置文件:将 动态库 的绝对路径添加到/etc/ld.so.conf文件中
# 使用以下命令,动态更新ld.so.cache,该文件直接影响动态链接器搜索动态库位置。
sudo ldconfig -v

makefile

  • 作用:进程项目管理。
  • 初步学习:1个规则、2个函数、3个自动变量
  • 语法
  • 要想使用默认的make命令,管理项目。makefile文件名:必须是"makefile"或者"Makefile"
目标:依赖条件
(一个tab缩进)命令
# 举例
hello:hello.c
	gcc hello.c -o hello
  1. 目标时间,必须晚于依赖条件的时间,否则,更新目标
  2. 依赖条件,如果不存在,寻找新的规则去产生依赖条件
hello:hello.o add.o sub.o mul.o
	gcc hello.c add.c sub.c mul.c -o hello
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
mul.o:mul.c
	gcc -c mul.c -o mul.o

2个函数

wildcard函数:用来匹配
src = $(wildcard ./*c)  :匹配当前工作目录下的所有.c文件。将文件名组成列表,赋值给变量src
相当于:src=add.c sub.c mul.c
patsubst函数:用来替换
obj = $(patsubst %.c,%.o,$(src)) :将参3中,包含参1部分,替换为参2
相当于obj=add.o sub.o mul.o
obj = $(patsubst %.c,%,$(src)) 
相当于obj=add sub mul

3个自动变量

  • 普通变量(自定义变量)
定义变量语法:变量名=变量值(都是字符串)
举例:
foo = abc
取变量值:$(变量)
举例:
bar = $(foo)===>bar=abc
  • 自动变量
$@:在规则命令中,表示规则中的目标
$^:在规则命令中,表示所有依赖条件
$<:在规则命令中,表示第一个依赖条件。如果将该变量应用在"模式规则"中,它可以将依赖条件列表中的每一个依赖,依次取出,套用模式规则

其他关键字

ALL:
	用来给makefile文件,指定"终极目标"
	makefile文件,默认规则为:从上到下,碰到第一 规则中的目标,为"终极目标"。我们可以使用ALL指定终极目标。
clean:
	用来借助makefile清除项目中的指定文件。如:*.o、a.out
	举例:
	clean:
		-rm -rf $(obj) a.out

模式规则

  • 可以将makefile文件中,具有严格格式的规则,使用模式规则代替。要求模式规则中,只能使用"$<"符号。
%.o:%.c
	gcc -c $< -o $@
  • 静态模式规则
$(obj):%.o:%.c
	gcc -c $< -o $@

伪目标

  • 针对,残缺的规则,也能使之生成目标。
.PHONY:clean ALL

其他参数

-n:模拟指定makefile,不真正执行!推荐首次编写makefile完成时,使用。
-f:指定命名为非"makefile"的文件。执行make命令

完成版的makefile

src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
CC = gcc
target = hello
ALL:$(target)
$(target):$(obj)
        $(CC) $^ -o $@
$(obj):%.o:%.c
        $(CC) -c $< -o $@
clean:
        -rm -rf $(obj) $(target)
.PHONY:clean ALL

GDB调试器

要求

  • 程序必须是自己编写的(能完全看懂),这样调试才有意义
  • 只能用来调试逻辑错误!
  • 必须添加-g参数,使用gcc编译生成的可以执行的文件,才能调试!

基础指令

命令解释
-g必须使用该参数编译可执行文件,否则没有调试表
gdb./a.out
list 1列出源码,根据源码指定行号设置断点。1代表从第一行开始
b 55在第55行添加断点
run/r运行程序,启动调试!
代码会自动运行,停止在断点处。断点对应的代码行,没有执行!
n/next下一条指令(越过函数,不进入函数)
s/step下一条执行(进入函数)
p/print打印变量值。如:p var。查看var变量的值。
continue继续执行断点后续的指令
finish结束当前函数调用
quit退出当前gdb调试
info b查看断点详细信息

其他指令

命令解释
start不使用断点,直接启动程序,开始单步调试
run找出程序出现段错误的位置。用法:gdb启动调试,直接run。停止的位置,就是代码出错的代码位置
set args 参1 参2 参3设置main函数命令行参数,必须在start/run之前设置
run 参1 参2 参3设置main函数命令行参数
b 23 if = 5设置条件断点。只能满足该条件时,断点才生效
disable 2设置编号为2号的断点,失效。使用info b查看
enable 3设置编号为3号的断点,生效。使用info b查看
delete 1删除编号为1号的断点
ptype查看变量类型
display设置跟踪变量。如display i。跟踪i的变量
undisplay取消跟踪变量。使用跟踪变量的编号。如:undisplay 2 。取消2号的变量跟踪
bt列出当前程序,正存活着的栈帧
frame根据栈帧编号,切换栈帧,例如:frame 1,切换到编号为1的栈帧

后记

学习很苦,但是为了生活不得不努力疯狂式学习。生活不会那么轻松,在大学,学的知识只是带我们入门,等毕业了才发现在大学学的东西不足以让我们找到合适的工作,只能用最短的时间学这些知识。此笔记整理,是为了让自己更好的理解,同时也希望此篇笔记能帮到有需要的人。
在这里插入图片描述

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值