作者:@小萌新
专栏:@Linux
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:介绍Linux的常用工具gcc/g++ 以及gbd
gcc / g++
gcc / g++的作用
gcc和g++分别是GNU的C和C++的编译器
我们都知道语言从源文件到可执行指令要分为以下四个步骤
- 预处理 (去除注释 头文件展开 宏替换 条件编译)
- 编译 (将c/c++ 代码翻译成汇编代码)
- 汇编 (将汇编代码转化为二进制语言)
- 链接 (将汇编过程产生的二进制语言进行连接)
为什么语言要经过这四步才能变为可执行指令
我们在上一些语言课的时候 一些学校里的教授可能跟我们讲过它们那个年代是怎么进行编程的
打孔编程
不过后面人们发现 这种打孔编程的指令很难让人记住并且效率极其低下 于是乎人们便发明出了汇编语言
从此之后我们变开始用汇编语言进行代码编程
汇编的语言的编译过程是这样子的
之后呢随着时代的进步 人们认为汇编语言还是太过复杂了 于是乎c语言就被发明出来了
之后c语言想要变成二进制文件就有两条路
c语言是直接变成二进制文件简单一点还是先变成汇编语言再变成二进制文件简单一点?
很显然 如果直接从c语言直接变成二进制文件的话等于前面几十年的努力全部被白费了
但是如果先变成汇编语言的话就简单很多 而且汇编语言变成二进制文件也是可以借鉴之前的经验的
当然由于C语言的编写中可能会存在大量的注释以及头文件的展开等
所以我们还需要预处理这一步骤将注释全部清除 将头文件展开
gcc / g++语法
我们常用的gcc语法是这样子的
gcc/g++ 选项 文件
下面是gcc g++的一些选项 其中前面七个选择特别重要 需要记住
- -E 只进行预处理 不生成文件 你需要把他重定向到一个输出文件里面(否则将把预处理后的结果打印到屏幕上)
- -S 编译到汇编语言
- -c 编译到目标代码(二进制文件)
- -o 将处理结果输出到指定文件 该选项后需紧跟输出文件名
- -static 此选项对生成的文件采用静态链接
- -shared 此选项将尽量使用动态库,生成文件较小
- -g 生成调试信息(若不携带该选项则默认生成release版本)
- -w 不生成任何警告信息
- Wall 生成所有警告信息
- -O0/-O1/-O2/-O3 编译器优化选项的四个级别 -O0表示没有优化 -O1为缺省值 -O3优化级别最高
预处理
预处理的作用包括下面四个
- 去除注释
- 头文件展开
- 宏替换
- 条件编译
接下来我们敲出下面的代码 让预处理之后的文件输出到test.i文件中
gcc -E test.c -o test.i
我们分别在C文件中添加上注释 头文件 宏替换和条件编译语句
我们可以发现经过预处理之后代码膨胀到了800多行 这是因为头文件展开的效果
条件编译和宏替换是同步进行的 因为N是100 非0表示真 所以执行的是
hello vim!
最后我们可以发现注释也全部消除了
编译
编译的作用包括下面两个
代码如下
gcc -S test.i -o test.s
- 检查代码语法是否有错误
- 将代码翻译成汇编语言
我们可以发现代码都变成汇编语言了
当然要是我们编写的代码中有一些语法的错误的话 在编译这一步就会停止
汇编
汇编的作用主要有一个
- 将汇编语言翻译成二进制语言
代码如下
gcc -c test.s -o test.o
我们可以发现这里变成了我们看不懂的乱码 实际上这里就是二进制语言
链接
链接的作用主要有一个
- 将生成的 .o文件(二进制文件) 进行链接
代码如下
gcc test.o -o testhv
之后我们便得到了一个可执行文件了
运行它 就能发现屏幕输出 hello vim!
动态库和静态库
函数库一般分为静态库和动态库两种:
- 静态库是指编译链接时 把库文件的代码全部加入到可执行文件当中 因此生成的文件比较大 但在运行时也就不再需要库文件了 静态库一般以.a为后缀
- 动态库与之相反 在编译链接时并没有把库文件的代码加入到可执行文件当中 而是在程序运行时由链接文件加载库 这样可以节省系统的开销 动态库一般以.so为后缀
映射到我们现实生活中
动态库就是网吧 你在宿舍里面写作业 当你遇到不会的题目的时候就回去网吧搜索 这道题目应该怎么做
而静态库就是你自己买了个电脑 以后遇到不会的题目就可以在自己宿舍查了
动态链接:
- 优点:省空间 bin体积小 加载速度快
- 缺点:依赖动态库 程序可移植性较差
静态链接:
- 优点:不依赖第三方库 程序的可移植性较高
- 缺点:浪费空间
我们的gcc/g++编译器默认使用的是动态链接
我们可以使用file指令查看
我们还可以使用ldd指令来查看可执行文件所依赖的库
其中的 /lib64/libc.so.6就是c语言标准库
我们可以使用 -static指令来强制进行静态链接
如果我们编译的过程中出现这个错误
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
这是由于我们的云服务器中没有安装静态库引起的
这个时候我们只需要下载一下静态库就可以了
下载指令如下
sudo yum install -y glibc-static libstdc++-static
这个时候我们使用ldd指令就可以发现
此外 因为静态链接里面包含了整个静态库 所以说代码会膨胀很多倍
这也刚好证明了动态链接的优点 省空间
gdb
debug和release
我们在C语言的学习阶段就知道了程序有两种发布版本
分别是 release 和 debug
- debug版本:程序本身会被加入更多的调试信息 以便于进行调试
- release版本:不会添加任何调试信息 是不可调试的
我们在linux中默认生成的文件都是release版本的 是不可以使用gbd调试的
如果我们想要它可被调试则需加入debug信息
具体指令如下
gcc test.c -o testhv_g -g
我们可以发现debug版本的代码确实比release代码大一点 这是因为多了调试信息
gdb指令
【进入gdb】
- gdb 文件名
【调试】
- 「run/r」:运行代码(启动调试)
- 「next/n」:逐过程调试
- 「step/s」:逐语句调试
- 「until 行号」:跳转至指定行
- 「finish」:执行完当前正在调用的函数后停下来
- 「continue/c」:运行到下一个断点处
- 「set var 变量=x」:修改变量的值为x (不常用)
【显示】
- 「list/l n」:显示从第n行开始的源代码 每次显示10行 若n未给出则默认从上次的位置往下显示
- 「list/l 函数名」:显示该函数的源代码
- 「print/p 变量」:打印变量的值
- 「print/p &变量」:打印变量的地址
- 「print/p 表达式」:打印表达式的值 通过表达式可以修改变量的值
- 「display 变量」:将变量加入常显示(每次停下来都显示它的值
- 「display &变量」:将变量的地址加入常显示
- 「undisplay 编号」:取消指定编号变量的常显示
- 「bt」:查看各级函数调用及参数
- 「info/i locals」:查看当前栈帧当中局部变量的值
【断点】
- 「break/b n」:在第n行设置断点
- 「break/b 函数名」:在某函数体内第一行设置断点
- 「info breakpoint/b」:查看已打断点信息
- 「delete/d 编号」:删除指定编号的断点
- 「disable 编号」:禁用指定编号的断点
- 「enable 编号」:启用指定编号的断点
【退出gdb】
- 「quit/q」:退出gdb
转载:https://blog.csdn.net/meihaoshy/article/details/129009074