Download presentation
Presentation is loading. Please wait.
1
第11章 gcc的使用与开发
2
主要内容 gcc简介 功能 命令 利用gcc编译c程序 利用make工具简化编译过程 make简介 Makefile基本格式 调试 静态调试
动态调试 gdb调试工具的使用
3
gcc简介 名称: GNU project C and C++ Compiler GNU Compiler Collection 管理与维护
预处理(Preprocessing) 编译(Compilation) 汇编(Assembly) 链接(Linking
4
gcc的使用 基本使用格式 常用选项及含义 $ gcc [ 选项 ] <文件名> gcc常用选项 选项 含义 -o file
将经过gcc处理过的结果存为文件file,这个结果文件可能是预处理文件、汇编文件、目标文件或者最终的可执行文件。假设被处理的源文件为source.suffix,如果这个选项被省略了,那么生成的可执行文件默认名称为a.out;目标文件默认名为source.o;汇编文件默认名为source.s;生成的预处理文件则发送到标准输出设备。
5
gcc的常用选项 gcc常用选项 选项 含义 -c
仅对源文件进行编译,不链接生成可执行文件。在对源文件进行查错时,或只需产生目标文件时可以使用该选项。 -g[gdb] 在可执行文件中加入调试信息,方便进行程序的调试。如果使用中括号中的选项,表示加入gdb扩展的调试信息,方便使用gdb来进行调试 -O[0、1、2、3] 对生成的代码使用优化,中括号中的部分为优化级别,缺省的情况为2级优化,0为不进行优化。注意,采用更高级的优化并不一定得到效率更高的代码。 -Dname[=definition] 将名为name的宏定义为definition,如果中括号中的部分缺省,则宏被定义为1
6
gcc的常用选项 gcc常用选项 选项 含义 -Idir
在编译源程序时增加一个搜索头文件的额外目录——dir,即include增加一个搜索的额外目录。 -Ldir 在编译源文件时增加一个搜索库文件的额外目录——dir -llibrary 在编译链接文件时增加一个额外的库,库名为library.a -w 禁止所有警告 -Wwarning 允许产生warning类型的警告,warning可以是:main、unused等很多取值,最常用是-Wall,表示产生所有警告。如果warning取值为error,其含义是将所有警告作为错误(error),即出现警告就停止编译。
7
gcc文件扩展名规范 gcc可以根据文件扩展名执行操作 gcc文件扩展名规范 扩展名 类型 可进行的操作方式 .c c语言源程序
预处理、编译、汇编、链接 .C,.cc,.cp,.cpp,.c++,.cxx c++语言源程序 .i 预处理后的c语言源程序 编译、汇编、链接 .ii 预处理后的c++语言源程序 .s 预处理后的汇编程序 汇编、链接 .S 未预处理的汇编程序 预处理、汇编、链接 .h 头文件 不进行任何操作 .o 目标文件 链接
8
使用gcc编译代码 源代码 示例源程序——hello.c #include <stdio.h> int main(void) {
printf("hello gcc!\r\n"); return 0; } 源代码
9
生成预处理文件 命令 $gcc –E hello.c –o hello.i 预处理文件hello.i的部分内容 ......
extern void funlockfile (FILE *__stream) ; # 679 "/usr/include/stdio.h" 3 # 2 "hello.c" 2 int main(void) { printf("hello gcc!\n"); return 0; } 命令 $gcc –E hello.c –o hello.i
10
生成汇编文件 命令 $gcc –S hello.c –o hello.s 汇编文件hello.s的部分内容 ...... main:
pushl %ebp movl %esp, %ebp addl $16, %esp movl $0, %eax leave ret ......" 命令 $gcc –S hello.c –o hello.s
11
生成二进制文件 生成目标文件 生成可执行文件 命令: $gcc –c hello.c –o hello.o
$gcc hello.c –o hello 运行程序 $./hello hello gcc!
12
编译多个文件 文件清单 greeting.h #ifndef _GREETING_H #define _GREETING_H
void greeting (char * name); #endif my_app.c #include <stdio.h> #include "greeting.h" #define N 10 int main(void) { char name[N]; printf("Your Name,Please:"); scanf("%s",name); greeting(name); return 0; } 文件清单 greeting.c #include <stdio.h> #include "greeting.h" void greeting (char * name) { printf("Hello %s!\r\n",name); }
13
目录结构(1) 目录结构(2) 编译命令 编译方式(1) 编译多个文件
$ gcc my_app.c greeting.c –o my_app 目录结构(2) 编译方式(1) $ gcc my_app.c functions/greeting.c –o my_app -I function greeting.h ./ greeting.c my_app.c greeting.h ./ greeting.c my_app.c functions
14
编译多个文件 目录结构(2) 编译方式(2) 分步编译 命令: 思路: 1、$gcc -c my_app.c -Ifunctions
2、$gcc -c functions/greeting.c 3、$gcc my_app.o greeting.o –o my_app 思路: 编译每一个.c文件,得到.o的目标文件; 将每一个.o的目标文件链接成一个可执行的文件;
15
使用make工具 适用场合:多个文件组成的软件项目 基本格式: 目标:欲生成的目标文件 依赖项:生成目标需要的文件 原理:
判断依赖项是否为最新,否则,生成新的目标 make工具的使用格式: make [[命令选项] [命令参数]] 通常使用make就可以了,make会寻找Makefile作为编译指导文件; 目标:依赖项列表 (Tab缩进)命令
16
使用make工具 Makefile示例 Makefile文件 1 my_app:greeting.o my_app.o 2
gcc my_app.o greeting.o -o my_app 3 greeting.o:functions\greeting.c functions\greeting.h 4 gcc -c functions\greeting.c 5 my_app.o:my_app.c functions\greeting.h 6 gcc –c my_app.c –Ifunctions Makefile示例
17
使用make工具 目标的依赖关系 my_app my_app.o greeting.o my_app.c
functions\greeting.h functions\greeting.c gcc –c my_app.c –Ifunctions gcc -c functions\greeting.c gcc my_app.o greeting.o -o my_app 目标的依赖关系
18
使用make工具 更实用的Makefile 更实用的Makefile文件 1 OBJS = greeting.o my_app.o 2
CC = gcc 3 CFLAGS = -Wall -O –g 4 my_app:${OBJS} 5 ${CC} ${OBJS} -o my_app 6 greeting.o:functions\greeting.c functions\greeting.h 7 ${CC} ${CFLAGS} -c functions\greeting.c 8 my_app.o:my_app.c functions\greeting.h 9 ${CC} ${CFLAGS} -c my_app.c -Ifunctions 更实用的Makefile
19
调试 静态调试: 在程序编译阶段查错并修正错误; 主要为语法错误: 输入错误; 类型匹配错误; 排错方式:
利用错误、警告信息,并结合源文件环境排错 动态调试: 在程序运行阶段差错并修正错误; 主要错误类型: 算法错误; 利用调试工具定位并修正错误;
20
调试举例 源文件 greeting.h #ifndef _GREETING_H #define _GREETING_H
void greeting (char * name); #endif my_app.c 1 #include <stdio.h> 2 #include "greeting.h" 3 #define N 10 4 int main(void) 5 { 6 char name[n]; 7 printf("Your Name,Please:"); 8 scanf("%s",name) 9 greeting(name); 10 /*return 0;*/ 11 } 源文件 greeting.c #include <stdio.h> #include "greeting.h" void greeting (char * name) { printf("Hello !\r\n"); }
21
静态调试举例 分块编译 my_app.c greeting.c 无错误
$gcc -g -Wall -c functions/greeting.c -g:将调试信息加入到编译的目标文件中 ; -Wall:将编译过程中的所有级别的警告都打印出来 ; 无错误 my_app.c $gcc -g -Wall -c my_app.c -Ifunctions 参数含义同上 错误信息:
22
调试举例 错误信息: 错误记录格式: 文件名:行号:错误描述 my_app.c: In function `main':
my_app.c:6: `n' undeclared (first use in this function) my_app.c:6: (Each undeclared identifier is reported only once my_app.c:6: for each function it appears in.) my_app.c:9: parse error before "greeting" my_app.c:6: warning: unused variable `name'
23
静态调试举例 分析、定位错误(警告): my_app.c的第6行: 描述含义: 分析: 改正: 这里取第2种改正方法;
n是一个没有声明的变量; 分析: 声明数字name时用到了变量n,但变量n在之前没有声明; 改正: 声明一个新变量n; 或者 将n改为宏N 这里取第2种改正方法;
24
静态调试举例 my_app.c的第9行: 描述含义: 在“greeting”之前出现解析错误; 分析:
改正: 第8行末尾增加“;” 重新编译 错误信息: my_app.c: In function `main': my_app.c:11: warning: control reaches end of non-void function
25
静态调试举例 分析、定位错误(警告): 警告:my_app.c的11行 描述含义: 控制以非空函数结束; 分析:
main函数返回类型为int,源程序没有以return 整数 形式结束; 改正: 将main改为返回void类型; 或者: 在main程序后增加return 返回语句; 采用第2种解决方式; 重新编译,无错误或警告信息,完成静态调试
26
静态调试举例 静态调试总结 主要为语法错误: 输入错误; 类型匹配错误; 分析信息: 主要来自gcc编译时产生的提示信息 错误警告定位:
不一定在提示信息描述的地方; 综合分析提示信息及提示行的上下文环境,定位并修正错误、警告; 有的警告可以不用修复.
27
动态调试举例 常见的动态调试方法: 增加调试语句 ; 记录程序的执行状况 ; 观察内存变化 ; 使用调试工具;
GNU Debuger的功能: 启动程序,设置程序执行的上下文环境; 在指定的条件下停止程序; 程序停止时,检查程序的状态; 在程序运行时,改变程序状态,使其按照改变后的状态继续执行。
28
动态调试举例 gdb常用的调试命令 命令 含义 file 指定需要进行调试的程序 step 单步(行)执行,如果遇到函数会进入函数内部
next 单步(行)执行,如果遇到函数不会进入函数内部 run 启动被执行的程序 quit 退出gdb调试环境 print 查看变量或者表达式的值 break 设置断点,程序执行到断点就会暂停起来 shell 执行其后的shell命令 list 查看指定文件或者函数的源代码,并标出行号
29
动态调试举例 对静态调试中的例子继续进行动态调试 工具:gdb 启动gdb 启动命令 启动提示 $gdb
GNU gdb Red Hat Linux (5.3post rh) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu". (gdb) 启动命令 启动提示 启动完毕
30
动态调试举例 调试指定程序(./my_app) 问题:期望的输出和实际输出不一致 加载调试程序 (gdb) file ./my_app
启动调试程序 程序输出 提示信息 (gdb) file ./my_app Reading symbols from ./my_app...done (gdb) run Starting program: /home/tom/shell_script/cpp/my_app/my_app Your Name,Please:tom Hello ! Program exited normally. (gdb)
31
动态调试举例 初次错误定位: 错误定位 输出有错误 重新开始一次调试; 启动gdb; 加载调试程序(./my_app); 查看程序源代码
命令: list 文件名
32
动态调试举例 (gdb) list my_app.c:1,20 1 #include <stdio.h>
2 #include "greeting.h" 3 #define N 10 4 int main(void) 5 { 6 char name[N]; 7 printf("Your Name,Please:"); 8 scanf("%s",name); 9 greeting(name); 10 return 0; 11 } (gdb) break 7 BreakPoint 1 at 0x : file my_app.c, line 7. 查看源代码 设置断点 提示信息 在程序第7行设置断点 命令: (gdb) break 7
33
动态调试举例 错误详细定位 1 (gdb) run 2
Starting program: /home/tom/shell_script/cpp/my_app/my_app 3 Breakpoint 1,main() at my_app.c:7 4 7 printf("Your Name,Please:"); 5 (gdb) next 6 scanf("%s",name); 7 8 Your Name,Please:tom 9 greeting(name); 启动调试程序 断点激活 步进下一步
34
动态调试举例 错误详细定位 (gdb) print name $1 = “tom\000ò·000©® (gdb) step
10 (gdb) print name 11 $1 = “tom\000ò·000©® 12 (gdb) step 13 greeting(name=0xbfffdf20 “tom”)at functions/greeting.c:5 14 printf(”Hello !\r\n”); 15 16 Hello ! 17 } 18 (gdb) kill 19 Kill the programe being debugged?(y or n)y 20 (gdb) quit 查看变量值 进入函数内部 步进执行 停止调试 退出gdb
35
动态调试举例 分析: 11行说明name变量被正确赋值(tom) 13行说明name变量值被正确赋予greeting的参数变量name
综合分析 错误出现在greeting.c的第5行; 原因: 输出字符串的格式不对; 改正错误
36
动态调试举例 动态调试总结 主要错误类型: 定位方法: 算法错误; 输入错误; 设置断点; 单步步进执行; 查看变量取值变化;
反复执行,逐步缩小错误范围;
37
课后习题 1、从文本源代码到可执行文件,gcc可以对哪些步骤进行控制?
2、编一个简单的helloworld程序,利用gcc控制程序生成的四个步骤。 3、简述gcc的用法和常用参数的含义。 4、上机查找gcc利用的库文件和头文件都放在什么路径下? 5、make工具如何使用?Makefile的基本格式是什么? 6、简述gdb的用法和常用命令的含义。
Similar presentations