Linux--gcc&g++的使用

由源码到可执行文件

我们知道要把我们所写的程序变成可执行文件需要进行4步操作才行,首先需要经过预处理(宏替换),在这个步骤会把引入的头文件进行展开,写的宏也会把它替换好。接着就是对程序进行编译,在这个步骤中会生成一个汇编代码。第三步,就是汇编,在汇编阶段会将编译过程生成的汇编代码生成机器可识别的代码。最后一步,就是链接,如果我们写的代码需要多个源文件,这一步就是将各个源文件连接起来。

预处理

在Linux中,使用gcc -E mycode.c -o mycode.i,这句指令就是对我们所写的代码进行预处理操作。它的文件后缀是.i,在这个文件中,我们可以看到它会将我们引入的头文件进行展开。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    printf("hello world\n");
    return 0;
}

在这里插入图片描述

编译

经过预处理后 ,我们得到了一个展开了头文件的.i文件,接着就是对这个文件进行编译让他生成一个汇编代码。执行gcc -S mycode.i -o mycode.s命令。在这个阶段,gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,把gcc代码翻译成汇编语言

在这里插入图片描述

汇编

紧接着就是对汇编代码进行汇编的工作,也就是将汇编代码生成机器可识别的代码。执行gcc -c mycode.s -o mycode.o,我们知道,机器能识别的代码是二进制代码,那就不是我们能看懂的了。

在这里插入图片描述

链接

最后一步就是对这个二进制文件进行链接操作生成可执行文件,语言也有库,它有一套头文件和一套库文件,需要连接来将代码中的函数调用、外部数据关联起来。执行gcc mycode.o -mycode.out.

在这里插入图片描述

函数库

  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的"stdio.h"中也只有该函数的声明,而没有定义函数的实现,系统把这些函数实现都被写到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径"/usr/lib"下进行查找。也就是链接到libc.so.6库函数中去,这样就能实现函数" printf"了,而这也就是链接的作用。
静态库和动态库

库函数一般分为静态库和动态库两种。

  • 静态库就是编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较打,但在运行时也就不要库文件了。其后缀名一般为".a"
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接加载库,这样可以节省系统的开销。动态库一般后缀名为 “.so”,如前面所述的libc.so.6就是动态库。gcc在编译时默认使用动态库。完成了链接之后,gcc就可以生成可执行文件

使用ldd mycode.out查看链接

在这里插入图片描述

gcc选项详解

  • -E 只激活预处理,这个不生成文件,需要把它重定向到一个输出文件里面
  • -S 编译到汇编语言不进行汇编和链接
  • -c 编译到目标代码
  • -o 将编译得到的文件输出到指定文件
  • -static 此选项对生成的文件采用静态链接
  • -g 生成调试信息。GNU调试器可以利用该信息
  • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统有动态库
  • -O0 、-O1、-O2、-O3 编译器的优化选项4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
  • -w 不生成任何警告信息
  • -Wall生成所有警告信息

Linux调试器-gdb的使用

程序的发布方式有两种,debug模式和release模式,Linux的gcc/g++出来的二进制程序默认是release模式,要使用gdb调试,必须在源代码生成二进制程序的时候加上-g选项

使用方法

前面说到gcc/g++编译器默认生成出来的可执行程序是release模式,而我们如果要使用gdb调试的话就需要生成出来的可执行的程序是debug模式。这就要使用一个参数-g,以此来生成可以调试的文件。

命令:gcc mycode.c -o mycode -g

我们重新写一下mycode中的代码,以便我们调试

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int SumToTop(int top)
  5 {
  6     int sum = 0;
  7     for(int i = 0; i <=top; ++i)
  8     {
  9         sum += i;
 10     }   
 11     return sum;
 12 }   
 13 int main()
 14 {   
 15     int top = 100;
 16     int result = SumToTop(top);
 17     printf("result = %d\n", result);
 18     return 0;
 19 }

首先我们先将mycode.c进行编译

在这里插入图片描述

通过这编译我们可以得到一个名为mycode的可执行文件。再使用 gdb mycode就可以进入调试模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DGlD3bSQ-1648483402727)(C:\Users\22114\AppData\Roaming\Typora\typora-user-images!在这里插入图片描述
)]

在gdb模式下,输入run就直接将整个程序运行完,如果想要退出gdb模式就输入quit指令,就可以退出gdb模式。

  • list 或 l 行号:显示程序的源代码,接着上次的位置往下,每次显示10行

在这里插入图片描述

  • list 或l 函数名 列出某个函数的源代码
  • r或run 运行程序
  • b或break 行号 在某一行打断点
  • info break或info b: 查看断点信息

在这里插入图片描述

PS:打好断断点后再使用run指令,程序会执行到断点处停下

  • s或step : 逐语句执行会进入调用函数函数

在这里插入图片描述

  • n或next: 逐过程执行,单条语句执行

  • finish: 执行到当前函数返回,然后停下来等待命令

在这里插入图片描述

  • delete breakpoints: 删除所有断点

在这里插入图片描述

  • delete breakpoints n: 删除序号为n的端点

在这里插入图片描述

  • disable breakpoints:禁用断点,也就是断点还在但是程序执行时不停在断点处
  • enable breakpoints:启用断点

在这里插入图片描述

  • display 变量名:跟踪查看一个变量名,每次停下来都显示它的值

在这里插入图片描述

在这里插入图片描述

  • undisplay:取消对先前设置的对那些变量的追踪

在这里插入图片描述

  • until x行号: 跳至x行
  • breaktrace(或bt):产看各级函数的调用以及参数

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_yiyi_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值