【回顾】
在(五)中,小编带领大家一起学习了文件查看和编辑命令,不知道大家还记得多少呢?
又忘记的或者记不清楚的朋友记得会看(五)昂!
一、编译链接
1、gcc,g++,gdb的安装
有的朋友可能会问,gcc、g++、gdb都是什么呢,我们就要安装。
gcc和g++大家应该可以猜到,gcc是运行C语言的工具,g++是运行C++的工具,而gdb则是调试工具。
在知道它们都是什么之后,我们就要学习安装它们啦!
类似于我们在(五)中安装vim,在命令行输入::sudo apt install gcc /g++/gdb
在安装过程中会让大家选择[y/n],大家输入y就好啦。
小编在安装g++时,顺手截的图,大家可以参考一下
有的小伙伴可能会出现有的安装包无法下载的问题,需要按照提示先输入sudo apt-get update,然后再输入sudo apt install gcc/g++/gdb就可以啦!
2、gcc分布编译链接
第一步——预编译:gcc -E main.c(自己编写的.c文件) -o main.i(生成的.i文件)
第二步——编译:gcc -S main.i(上一步的.i文件) -o main.s(生成的.s文件)
第三步——汇编:gcc -c main.s(第二步的.s文件) -o main.o(生成的.o文件)
第四步——链接:gcc main.o(第三步的.o文件) -o main(生成的.out文件)
执行:./main 或者 全路径/main
执行main
3、编译链接过程
原理:
main.c通过预编译生成main.i文件
main.i通过编译生成main.s文件
main.s通过汇编生成main.o文件(可重定位的二进制目标文件)
链接就是将所有的.o文件,.a文件(静态库文件),.lib文件,.obj文件链接起来,生成.out文件(ELF格式的可执行文件)(在Windows系统是生成.exe文件)
让我们一起总结一下:预编译生成.i文件(第一步),编译生成.s文件(第二步),即编译生成汇编指令,然后接下来当然就是汇编了,对汇编指令进行汇编,生成.o文件(第三步),即变成二进制指令(第三步),最后就是链接了(第四步)。
小编在这里向大家重点强调这个编译链接过程非常的重要。大家必须要熟练掌握,不能出错。当面试官询问大家编译链接的过程是什么时,大家连这四个步骤都不能说正确就不会有接下来的问题了,因为已经被淘汰。
二、gcc的执行
1、gcc如何执行
路径+可执行文件名 或者 路径+可执行文件名 &(将进程放到后台执行);
(补充)大家可以把可执行文件放到/usr/bin就可以省略路径了;
这是为什么呢?
大家可以想一下,为什么我们执行ls、pwd这些命令(本质也是人写的程序)可以不用加路径,这是因为它们在bin目录里,也就是它们的路径为/user/bin,我们在(二)中学习目录结构时,让大家记住过bin目录的作用是存放常用的命令(二进制可执行程序),当我们把程序放在这个路径下,就可以直接输入可执行文件名进行执行啦。
2、两步执行与一步执行
(一)两步执行
将三步合为一步,即不经过预编译,编译,汇编三步,直接一步生成.o文件,然后链接执行:
gcc -c main.c -o main.o(这一步在工作中常用,只编译,查看是否出现语法错误)
gcc -o main main.o
(二)一步执行
将四步合为一步:gcc -o main main.c
3、多文件的编译执行
首先,大家要先准备多个文件,这里小编准备的是add(求和)、max(求最大值)、main(主函数),一共有五个文件,包含两个.h文件,三个.c文件。
//add.h
int add(int x, int y);
//add.c
int add(int x, int y)
{
return x+y;
}
//max.h
int max(int x,int y);
//max.c
int max(int x, int y)
{
return x>y?x:y;
}
//main.c
#include <stdio.h>
#include "./max.h"
#include"./add.h"//不写路径默认当前位置,写可以是相对路径"./add.h"也可以是绝对路径"/home/stu/quzijie/class03/test06"
int main()
{
int a=10;
int b=20;
printf("a+b=%d\n",add(10,20));
printf("a,b的最大值为%d\n",max(10,20));
return 0;
}
执行:
(两步执行)
gcc -c main.c
gcc -o main main.c add.c max.c
这里可能会有小伙伴这样写:gcc -o main main.c,不能这样写哦,这个是错误的,因为在main.c里面还使用了add和max。
(一步执行)
gcc -o main main.c add.c max.c
三、gdb调试
1、debug版本与release版本
debug版本:
在编译阶段会加入某些调试信息;
调试信息是在编译的过程中加入到中间文件.o文件的;
gcc -c main.c -g:生成包含调试信息的中间文件
gcc -o main main.o
一步执行:gcc -o main main.c -g
release版本:
发行版本,没有调试信息;
gcc默认生成的为release版本,因此才需要上面的命令生成debug版本,然后才能使用gdb调试
2、gdb命令
这些命令希望大家可以经常使用,多多练习才能掌握。
gdb 可执行文件名
显示代码:l
加断点:b 行号
启动程序:r(运行之前一定要加断点)
查看断点信息:info break/info b
删除断点信息:delete 断点编号
单步执行:n
打印:p
显示:display 变量名
退出:q
(gdb命令——全)
I:显示main函数所在的文件的源代码
list 文件名:num显示文件名文件num行上下的源代码(多文件)
b 行号:给指定行添加断点
b 函数名:给指定函数的第一有效行添加一个断点
info break:显示断点信息;(info b)
delete 断点号:删除指定断点
r(run):运行程序
n(next):单步执行
c(continue):继续执行,直接执行到下一个断点处
s:进入将要被调用的函数中执行
finish:跳出函数;
q:退出调试
bt:显示函数调用栈
disable 断点号:将断点设定为无效的,不加断点号,将所有断点设置为无效
enable 断点号:将断点设定为有效的,不加断点号,将所有断点设置为有效;
p val:打印变量val的值
p &val:打印变量val的地址
pa+b:打印表达式的值
p arr(数组名):打印数组所有元素的值
p *arr@len:用指向数组的指针打印数组所有元素的值
display:自动显示,参数和p命令一样;
info display:显示自动显示信息
undisplay+编号:删除指定的自动显示
ptype val:显示变量类型
3、补充命令
多进程的调试命令:
(gdb) set follow-fork-mode mode
mode可以选择parent或者child,即:选择调试哪个进程
注意:未被跟踪调试的进程会直接执行结束;
多线程调试命令:
1)利用info threads查看线程信息;
2)thread id:调试目标id指定的线程;
3)set scheduler-locking off|on|step;
“off"表示不锁定任何线程;
“on"只有当前被调试的线程继续运行;
“step"在单步执行的时候,只有当前线程会执行;
4、总结调试命令步骤
(1)gcc -o main main.c -g
(2)gdb 可执行文件名
(3)显示代码:l
(4)加断点:b 行号
(5)启动程序:r(运行之前一定要加断点)
(6)显示:display 变量名
四、makefile安装及make自动化编译
1、安装makefile
还是和之前几次的安装方法一样,在命令行输入::sudo apt install make
在安装过程中会让大家选择[y/n],大家输入y就好啦!
上图是小编在安装makefile时的截图,大家可以参考一下。
有的小伙伴可能会出现有的安装包无法下载的问题,需要按照提示先输入sudo apt-get update,然后再输入sudo apt install gcc/g++/gdb就可以啦!
2、makefile文件的运用
makefile文件:
Linux上的工程管理工具,可以实现自动化编译;工程中的源文件不计其数,可以根据模块,功能等存储在不同的目录中;
makefile可以提高编译效率,使用make命令每次只会编译那些修改了的或者依赖修改了的这些文件,没有修改的文件不会重新编译。
VS底层就有自己的makefile文件;
我们还是使用上面引入的add、max、main的代码。
大家一起跟着小编动手写makefile文件吧!
上面这个图片就是小编的练习成果啦,大家在自己编写的过程中一定要注意顶格与tab键,了解makefile文件的生成规则,在图片中小编也标注了让大家注意tab键与空格是不一样的,一定要注意字的颜色,以及生成规则!
3、总结
makefile可以提高编译效率,使用make命令每次都只会编译那些修改了的或者依赖修改了的文件(间接修改),没有修改的文件不会重新编译;