【Linux】编译器gcc和g++与调试器gdb的使用

这篇具有很好参考价值的文章主要介绍了【Linux】编译器gcc和g++与调试器gdb的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Linux编译器-gcc/g++

1.程序运行的四个阶段

我们知道,一个程序被运行起来之后需要经历四个阶段然后才变成一个可执行的程序,他们分别为:预处理,编译,汇编和链接。下面我们将介绍这四个阶段的操作,测试代码如下:

#include <stdio.h>
// 宏定义
#define N 10

int main()
{
	// 测试注释
	// printf("hello 1\n");
	// printf("hello 2\n");
	// printf("hello 3\n");
	// printf("hello 4\n");
	printf("hello 5\n");
	printf("hello 6\n");
	printf("hello 7\n");
	printf("hello 8\n");
	printf("hello 9\n");
	printf("hello 10\n");

	// 测试宏
	printf("%d\n", N);

	// 测试条件编译
#ifdef SHOW
	printf("hello SHOW\n");
#else
	printf("hello DEFAULT\n");
#endif

	return 0;
}

1.1 预处理

预处理也叫预编译,程序在预处理阶段会完成如下操作:

展开头文件,将头文件中的代码拷贝到当前代码中

删除注释

执行条件编译

完成#define定义的符号,宏的替换以及删除

在Linux下我们可以通过如下指令就可以得到经过预处理之后的代码

gcc -E test.c -o test.i

gcc : 表示使用gcc编译器来编译该代码

-E :表示让代码完成预处理之后就停下来

test.c : 我们要编译的代码

test.i:预处理产生的文件一般以.i为后缀

-o test.i :用于指明临时文件的名称(test.i),经过预处理之后它会形成一个名称为test.i的临时文件,而不是输出到终端上

【Linux】编译器gcc和g++与调试器gdb的使用

【Linux】编译器gcc和g++与调试器gdb的使用

我们可以看到,经过预处理之后,头文件stdio.h中的内容全部会被拷贝到test.i中,所以test.i一个有800多行,我们注释的内容也全部被删除,宏定义被替换,条件编译被执行

1.2 编译

程序在编译阶段会完成如下操作:

语法分析

词法分析

语义分析

符号汇总

我们通过如下指令来获取程序编译之后的代码:

gcc -S test.i -o test.s

-s:表示让代码在完成编译之后停下来,不再继续之后后面的过程

编译产生的文件一般以.s为后缀

【Linux】编译器gcc和g++与调试器gdb的使用

【Linux】编译器gcc和g++与调试器gdb的使用

我们可以看到,编译阶段会将高级语言转换成汇编语言

1.3 汇编

汇编阶段会将编译阶段生成的汇编代码转换成计算机可以识别的二进制目标代码,其中生成的.o文件被称为可重定向的二进制目标文件

我们通过如下指令来获取程序汇编之后的代码:

gcc -c test.o -o test.s

-c:表示让代码在完成汇编之后停下来,不再继续往后执行

汇编产生的文件一般以.s为后缀

【Linux】编译器gcc和g++与调试器gdb的使用

【Linux】编译器gcc和g++与调试器gdb的使用

这样我们就得到了二进制目标文件,但我们使用一般的文本编辑器打开发现是一堆我们看不见的符号,我们可以通过如下指令以指定的格式打开它(默认是八进制):

od test.o

【Linux】编译器gcc和g++与调试器gdb的使用

1.4 链接

程序在链接的过程中会完成如下操作:

1.合并段表,编译器会把汇编阶段生成的多个文件中相同格式的数据合并到一起,最终形成一个.exe文件

2.符号表的合并和重定位,符号表的合并是编译器会把在汇编阶段生成的多个符号表合成一个符号表,重定位是当同一个符号出现在两个符号表中时,编译器会选取其中一个有效的地址相关的一个,舍弃另外一个

在Linux中,链接我们直接使用gcc即可,如果我们没有指定将生成的临时文件的话,默认会将结果存放在a.out中

gcc test.o //默认
gcc test.c -o test.out // 保存到test.out文件中

【Linux】编译器gcc和g++与调试器gdb的使用

【Linux】编译器gcc和g++与调试器gdb的使用

我们最后通过链接得到的文件称为可执行程序,它里面保存的也是计算机能够识别的二进制指令

我们两个文件都可以输出最终的结果:

【Linux】编译器gcc和g++与调试器gdb的使用

虽然我们将gcc编译代码分为预处理,编译,汇编和链接,但是我们在日常生活中运行代码时,直接使用"gcc test.c -o test.out"或者"gcc test.c"即可,这里分为四个阶段是为了让我们更好的理解程序的运行过程

2.链接方式与函数库

2.1 动态链接与静态链接

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?

最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用

这是因为我们在编写代码的时候,除了自己实现的函数外,比如printf函数我们会去调用函数库中的代码,但是stdio.h里只有函数的声明,没有函数的实现。此外,程序在预处理,编译和汇编阶段处理的都是我们自己的代码,只有在链接的时候,库函数的实现才会和我们的代码关联起来(符号表的重定位),所以,链接的本质是我们在调用库函数的时候如何与标准库相关联的问题,程序一共有两种链接方式:动态链接和静态链接

动态链接

动态链接是指执行代码的时候,如果遇到库函数调用就跳转到动态库中对应的函数的定义的地方,然后执行该函数,执行完毕后再跳转到原程序处然后继续往后执行,它的优点就是形成的可执行程序小,缺点是受动态库变动(删除,升级等)的影响

静态链接

静态链接是直接将程序需要使用的库函数都从对应的静态库中拷贝一份到原程序中,它的优点是不受静态库(删除,升级等)的影响,缺点是形成的可执行程序大

2.2 动态库与静态库

函数库是一些事先写好的,用于给别人使用的函数的集合,函数库分为静态库和动态库

静态库

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。在Linux在其后缀名一般为“.a“,在windows在的后缀名为”.lib“

动态库

动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。在Linux下动态库一般后缀名为“.so”,在windows下其后缀名为“.dll”

【注意】

1.动态链接必须使用动态库,静态链接必须使用静态库,即进行动态链接时只能跳转到动态库中对应的函数实现处,进行静态链接时只能拷贝静态库中的函数实现

2.gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,gcc默认生成的二进制程序,是动态链接的.原因如下:

  • 如果使用静态链接,那么程序形成的可执行程序大,此时,不仅仅占用磁盘的空间大,其被运行时加载到内存所占用的空间也会很大,而我们的内容有限,运行过大的程序可能会导致卡死无法运行
  • 虽然动态链接受库函数变动的影响,但是库函数一般是很少变动的,即使变动也会兼容以前的版本,所以对程序的影响不大
  • 在Linux下,我们可以使用"file"指令来辨别文件的类型,使用"ldd"来打印或查看程序运行所 需要的共享库

【Linux】编译器gcc和g++与调试器gdb的使用

Linux一般会自动安装C语言动态库,因为Linux下的大多数指令以及我们默认使用的gcc编译得到的可执行程序都是动态链接的,依赖于C动态库,但是C静态库,C++静态库可能就需要我们自己进行安装。我们可以使用如下命令来安装C和C++的静态库:

sudo yum install -y glibc-static
sudo yum install -y libstdc++-static

我们可以使用"-static"选项来指定程序使用静态方式进行链接:

【Linux】编译器gcc和g++与调试器gdb的使用

我们可以看到,使用静态链接方式形成的可执行程序比动态链接方式形成的可执行程序的要大100倍左右,即一个动态链接只有1M的文件,使用静态链接方式形成的可执行程序就有几百M,两者之间相差非常大,所以Linux默认使用静态链接的方式

3.gcc/g++的使用

在Linux在,我们可以使用如下指令来安装gcc和g++:

sudo yum install -y gcc
sudo yum install -y gcc-g++ libstdc++-devel

gcc与g++的使用如下:

-E 只激活预处理,在完成预处理后停下来,不再往后继续执行,生成以.i为后缀的文件

-S 在完成编译后停下来,不再继续往后执行,生成的文件以.o为后缀 编译到汇编语言不进行汇编和链接

-c 在完成汇编之后停下来,不再继续往后执行,生成以.o为后缀的文件 编译到目标代码

-o 将输出到终端的内容保存到指定的文件中

-static 此选项对生成的文件采用静态链接

-g 以debug的方式发布软件,生成调试信息。GNU 调试器可利用该信息。

-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

-O0-O1-O2-O3 编译器的优化选项的4个级别

-O0表示没有优化,这是默认的编译选项

-O1为缺省值,编译器会在不花费太多编译时间的同时试图生成更快更小的代码。这些优化是非常基础的,但一般这些任务肯定能顺利完成

-O2 -O2会比-O1启用多一些标记。设置了-O2后,编译器会试图提高代码性能而不会增大体积和大量占用的编译时间

-O3优化级别最高 在O2的基础上进行更多的优化,用这个选项会延长编译代码的时间,并且在使用gcc4.x的系统里不应全局启用

-w 不生成任何警告信息。

-Wall 生成所有警告信息。

二、Linux调试器–gdb

1.debug与release

在windows中使用VS的时候我们知道,程序的发布方式一共有两种-debug模式和release模式,其中debug模式是给程序员使用的,其中包含调试的各种信息,程序员可以根据这些调试信息对程序进行修改和完善,而release模式则是给用户使用的,它不包含调试信息,因为用户不负责也不关心对程序进行调试。

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

#include <stdio.h>
#include <time.h>

int AddToVal(int from,int to)
{
    int sum=0;
    int i=0;
    for(i=from;i<=to;++i)                                                                     {
        sum+=i;
    }
    return sum;
}
void Print(int sum)
{
    long long timestamp=time(NULL);
    printf("result=%d,timestamp:%lld\n",sum,timestamp);
}
int main()
{
    int sum=AddToVal(0,100);
    Print(sum);
    return 0;
}

【Linux】编译器gcc和g++与调试器gdb的使用

【Linux】编译器gcc和g++与调试器gdb的使用

我们可以发现,以debug方式发布的和以release方式发布的程序无论是在大小,程序内部的包含的相关的调试信息,还是debug模式下是否具有调试样例都是由明显区别的

2.gdb 的使用

当我们使用-g选项的时候就可以得到以debug模式发布的可执行程序,然后我们就可以使用gdb对其进行调试了:

gdb的安装

在Linux在,我们可以使用如下指令来安装gdb:

sudo yum install -y gdb

gdb调试的常见选项如下:

list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。我们第一次使用l显示源代码后,我们下一次再使用l或者下一次使用enter时,它会接着上一次的位置接着向下显示

list/l 函数名:列出某个函数的源代码。

r或run:运行程序。调试运行,如果程序中有断点,则在断点处停下来,如果没有,则直接 将程序执行完毕,相当于VS中的F5

n 或 next:单条执行。逐过程调试,相当于VS的F10

s或step:进入函数调用 逐语句调试,相当于VS的F11

break(b) 行号:在某一行设置断点,相当于VS的F9

break 函数名:在某个函数开头设置断点

info break :查看断点信息。

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

print§:打印表达式的值,通过表达式可以修改变量的值或者调用函数

p 变量:打印变量值。

set var:修改变量的值

continue(或c):从当前位置开始连续而非单步执行程序 运行至下一个断点处停下来,如果断点所在行不是一条语句,比如"{" “}” 或者空行,那么它会继续往后继续执行到有效行处

run(或r):从开始连续而非单步执行程序

delete breakpoints:删除所有断点

delete breakpoints n:删除序号为n的断点 (d 断点编号),每个断点都有自己的编号,我们删除断点时需要指明对应的断点编号

disable breakpoints:禁用断点

enable breakpoints:启用断点

info(或i) breakpoints:参看当前设置了哪些断点

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

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

until X行号:跳至X行

breaktrace(或bt):查看各级函数调用及参数

info(i) locals:查看当前栈帧局部变量的值

quit:退出gdb

我们重点掌握下面的即可:

【Linux】编译器gcc和g++与调试器gdb的使用

指令演示

l行号显示源代码

【Linux】编译器gcc和g++与调试器gdb的使用

l 函数显示该函数的源代码

【Linux】编译器gcc和g++与调试器gdb的使用

r 运行程序

【Linux】编译器gcc和g++与调试器gdb的使用

b 行号打断点,info b查看断点,d 断点编号 删除断点

【Linux】编译器gcc和g++与调试器gdb的使用

r 调试运行

【Linux】编译器gcc和g++与调试器gdb的使用

n 逐过程调试,s逐语句调试

【Linux】编译器gcc和g++与调试器gdb的使用

c 运行至下一个断点处停下

【Linux】编译器gcc和g++与调试器gdb的使用

bt 查看调用堆栈

【Linux】编译器gcc和g++与调试器gdb的使用

p 变量,查看变量值,display 跟踪查看变量 undisplay取消跟踪

【Linux】编译器gcc和g++与调试器gdb的使用

finish 把当前函数运行完,q 退出gdb1

【Linux】编译器gcc和g++与调试器gdb的使用文章来源地址https://www.toymoban.com/news/detail-470292.html

到了这里,关于【Linux】编译器gcc和g++与调试器gdb的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【UNIX 环境编程】GCC 编译器 | Makefile 基础入门 | GDB 调试教学

    💭 写在前面: 本文将介绍如何使用 GCC 编译器编译,并详细介绍了 Makefile 的基本构造、创建Makefile 文件以及 Makefile 变量,以提高编译效率。此外,本文还将探讨GDB调试器的使用,包括调试前的准备、readelf 读取 ELF 文件信息、显示代码、断点、调试、监视、跳转等内容。 

    2024年02月03日
    浏览(71)
  • 为 Microsoft C++ 配置 VS Code在本教程中,您将配置 Visual Studio Code 以在 Windows 上使用 Microsoft Visual C++ 编译器和调试器

    在本教程中,您将配置 Visual Studio Code 以在 Windows 上使用 Microsoft Visual C++ 编译器和调试器。 配置完 VS Code 后,你将在 VS Code 中编译和调试一个简单的 Hello World 程序。本教程不教您有关 Microsoft C++ 工具集或 C++ 语言的详细信息。对于这些主题,网上有很多很好的资源。 如果您

    2024年02月10日
    浏览(75)
  • Linux开发工具大全 - 软件包管理器yum | vim编辑器 | gcc/g++编译器 | 自动化构建工具Make/Makefile | gdb调试工具

    目录 Ⅰ.  Linux 软件包管理器 yum 一、yum 背景知识 二、yum 的基本使用 1、查看软件包 2、软件包名称构成 3、安装软件 4、卸载软件 Ⅱ.vim编辑器  一、认识vim 1、vim概念  2、模式及其切换  二、vim使用 1、vim的指令(重要)  命令模式 插入模式 底行模式 2、vim配置 Ⅲ.gcc/g++编

    2024年02月05日
    浏览(55)
  • [linux初阶][vim-gcc-gdb] TwoCharter: gcc编译器

    目录 一.Linux中gcc编译器的下载与安装 二.使用gcc编译器来翻译 C语言程序  ①.编写C语言代码 ②翻译C语言代码 a.预处理 b.编译  c.汇编  d.链接 ③.执行Main 二进制可执行程序(.exe文件)  三.总结  使用yum命令(相当于手机上的应用市场)来进行安装.  下载完毕之后,使用 which gc

    2024年04月10日
    浏览(59)
  • Linux--调试器:gdb

    gcc与g++默认动态链接形成的可执行程序(比如a.out)是 release 版本,不可调试!!! 如何搞成debug可调试版本? 查看可执行程序存储了哪些内存空间:   调试语法:

    2024年02月13日
    浏览(51)
  • Linux——gdb调试器

    目录    前言: 二.gdb定义及指令: 如何查看该exe文件是否为Debug版本?两种方法: 三.gdb调试:         调试指令1:l指令(小写L) run指令:运行程序,相当于VS中的直接运行不调试——可简化输入r  break指令:设置断点——指令可简化输入为b ​编辑  info b指令:查看整个代码

    2024年02月07日
    浏览(38)
  • Linux调试器gdb

    本文已收录至《 Linux知识与编程 》专栏! 作者: ARMCSKGT 演示环境: CentOS 7     ​ 目录 前言 正文 下载gdb 生成可调式文件 进入gdb gdb常用指令 查看代码 l  运行程序 r  断点设置 b  显示信息 info  查看断点 info b  删除断点 d  禁用断点 disable breakpoints  启用断点 enable brea

    2024年02月14日
    浏览(54)
  • Linux - 还不懂 gdb 调试器?(调试软件)

    当前,我们可以使用 make/makefile 来程序化执行代码文件;可以使用 gcc/g++ 等编译器来编译代码;可以使用 vim 编辑器来编写代码;其实在 Linux 当中还有一个工具,可以实现调试工作,这个工具就是 -- gdb。 在了解调试器之前,你应该对代码的发布版本做一些了解: 我们在 VS

    2024年02月07日
    浏览(54)
  • Linux调试器之gdb

    我们前面介绍了几个基本的环境开发工具。例如通过yum我们可以安装和卸载软件、通过vim我们可以写代码、通过gcc和g++我们可以编译代码成可执行程序。但是如何在Linux下调试代码呢?我们并未介绍,本期我们将来介绍最后一个工具 --- 调试器gdb。 程序的发布方式 gdb基本的调

    2024年04月16日
    浏览(67)
  • 【Linux】Linux调试器-gdb使用

    程序的发布方式有两种,debug模式和release模式 Linux gcc/g++出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项 退出:  调试命令: list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。 list/l 函数名:列出某

    2024年02月21日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包