第4章 linux中的编译器GCC/G++和调试器GDB
创始人
2024-06-02 22:37:09

1.1 简介

对于.c 格式的C文件,可以采用 gcc 或 g++编译。

对于 .cc、.cpp 格式的C++文件,应该采用 g++进行编译。

常用的选项:

选项

作用

-c <源文件>

表示编译源文件(.c,.cpp,.cc等)

-o <输出文件>

表示输出目标文件(.o)

-g

表示在目标文件中产生调试信息,用于 gdb 调试

-D <宏定义>

编译时将宏定义传入进去

-Wall

打开所有类型的警告。

注意:这个编译器编译出来的文件是为了在X86的linux系统环境下运行的。

1.2 gcc的编译过程

过程:预编译à编译à汇编à链接

当我们进行编译的时候,要使用一系列的工具,我们称之为工具链。其中包括:预处理器、编译器、汇编器as、连接器。

一个编译过程可以用图2.1 来表示, 包括下面几个阶段:

(1)预处理:预处理器将对源文件中的宏进行展开。

(2)编译:gcc 将 c 文件编译成汇编文件(.s)。

(3)汇编:as 将汇编文件编译成机器码(.o)。

(4)链接:将目标文件和外部符号进行连接,得到一个可执行二进制文件。

1.3 gcc所支持的后缀

后缀名

所对应的语言

后缀名

所对应的语言

.c

C原始程序

.s/.S

汇编语言原始程序

.C/.cc/.cxx

C++原始程序

.h

预处理文件(头文件)

.m

Objective.c原始程序

.o

目标文件

.i

已经预处理的C原始程序

.a/.so

编译后的库文件

.ii

已经预处理的C++原始程序

1.4 gcc常用选项

选项

含义

-E

只预编译,不做任何处理

-c

只编译不链接,生成目标文件”.o”

-S

只编译不会汇编,生成汇编代码”.s”

-g

在执行过程中包含标准调试信息

-o file

指定将file文件作为输出文件

-v

打印出编译器内部编译各过程的命令行信息和编译器的版本

-I dir

在头文件的搜索路径列表中添加dir目录

例子:

下面以一个很简单的test.c 来探讨这个过程。

#include 
#define NUMBER (1 + 2)
int main()
{int x = NUMBER;return 0;
}
  1. 预处理: gcc -E test.c -o test.i。

我们用cat 查看 test.i 的内容如下:

    ......        //大多都是stdio.h文件内容# 943 "/usr/include/stdio.h" 3 4# 3 "test.c" 2int main(void){int x = (1+2);return 0;}

我们可以看到,文件中宏定义NUMBER 出现的位置被(1+2)替换掉了,还有把stdio.h的内容都添加进来了。

  1. 编译: gcc -S test.i -o test.s。

通过cat test.s 查看test.s 的内容为汇编代码如下:

junjia@junjia:~/works/3rd_day/1st_test$ cat test.s.file    "test.c".text.globl    main.type    main, @functionmain:.LFB0:.cfi_startprocpushl    %ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl    %esp, %ebp.cfi_def_cfa_register 5subl    $16, %espmovl    $3, -4(%ebp)movl    $0, %eaxleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc.LFE0:.size    main, .-main.ident    "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4".section    .note.GNU-stack,"",@progbitsjunjia@junjia:~/works/3rd_day/1st_test$ 
  1. 汇编: as test.s -o test.o 。

利用as 将汇编文件编译成机器码。得到输出文件为 test.o,test.o 中为目标机器上

的二进制文件。

用 nm 查看文件中的符号: nm test.o ,输出如下:

00000000 T main

有的编译器上会显示:

00000000 b .bss 00000000 d .data 00000000 t .text U ___main U __alloca 00000000 T _main 

既然已经是二进制目标文件了,能不能执行呢?

试一下./test.o,提示 cannot execute binary file。

因为是有U这样的符号的地址没有定下来。

  1. 链接:gcc -o test test.o。

将所有的.o 文件链接起来生成可执行程序,这个时候的test就可以执行了。

一般我们编译文件没有必要那么多步骤,只要如下就够了:

gcc -o teat test.c

步骤总结:

预处理阶段:对包含的头文件(#include)和宏定义( #define、 #ifdef 等)进行处理。

gcc –E hello.c –o hello.i 
//-o 表示输出为指定文件类型 -E 将源文件( *.c) 转换为( *.i)

编译阶段:检查代码规范性、语法错误等,在检查无误后把代码翻译成汇编语言。

gcc –S hello.i –o hello.s 
//-S 将已预处理的 C 原始程序( *.i)转换为( *.s) 

链接阶段:将.s 的文件以及库文件整合起来链接为可执行程序。

gcc –o hello.exe hello.s 
//最后将汇编语言原始程序(*.s)和一些库函数整合成( *.exe) 

示例1:几种编译过程。

#include 
#define MAX 100
#define max(a, b) ((a) > (b) ? (a) : (b)) //宏定义,执行-E 之后被替换
main()
{printf("MAX=%d\n", MAX);printf("max(3,4)=%d\n", max(3, 4));
}

//法一:

gcc –E project1.c –o project1.i //预编译,生成已预编译过的 C 原始程序*.i

gcc –S project1.i –o project1.s //编译,生成汇编语言原始程序*.s

gcc –o project1.exe project1.s //链接,生成可执行程序

//法二:

gcc –c project1.c –o project1.o //编译

gcc –o project1.exe project1.o //链接

//法三:

gcc –o project1.exe project1.c //编译并链接

示例2:-D选项的使用。

#include 
main()
{#ifdef lry //表示如果定义了 lry,即命令行参数传了 lry,就执行下面的输出printf("lry is defined!\n");#elseprintf("lry is not defined!\n");#endifprintf("main exit\n");
}

编译过程:

gcc –E project2.c –o project2.i –D lry

//条件编译,用-D 传递,如果没有传 lry 则执行#else

gcc –S project2.i –o project2.s

gcc –o project2.exe project2.s

或:gcc –o project2 project2.c –D lry

1.5 gdb调试器

作用:对c/c++程序进行调试的。

1.让程序停止在指定的某处

2.当程序停住时,可以查看程序的运行状态(比如:变量值)

gdb命令&调试步骤

第1步:编译程序

gcc -g a.c -o a.out

第2步:启动GDB

gdb a.out //运行调试器并打开调试文件

或者:

gdb //运行gdb

file a.out //打开调试文件

第3步:打断点

break 函数名 //在函数入口处打断点

或者

break 行号 //在某行打断点

第4步:运行程序

run

其他命令:括号内是命令的简写。

序号

命令

作用

1

next,continue

2

list(l)

3

break(b)

函数名/行号/文件名:行号

4

break行号 if 条件

break 5 if k=8

5

info break

查看断点信息

6

delete <断点编号>

删除断点

7

run(r)

全速运行到断点处

8

next(n)

单独运行,但不进入子函数

9

step(s)

单独运行,但进入子函数

10

continue(c)

11

print(p)

12

finish

13

watch 变量名

查看变量的值

下一小节:Makefile的使用

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...