实验五常用软件开发工具.docx
《实验五常用软件开发工具.docx》由会员分享,可在线阅读,更多相关《实验五常用软件开发工具.docx(19页珍藏版)》请在冰豆网上搜索。
实验五常用软件开发工具
实验五、常用软件开发工具
一、实验目的
1、熟悉字符模式下的C程序编译和调试环境,基本掌握Linux字符模式下的编译工具
和调试工具的使用;
2、本实验需要综合使用Linux基本文件命令、编辑器的使用,练习在Linux的字符模
式下,编辑、编译及调试一个C程序的基本方法。
二、实验内容和步骤
1gcc和g++语言编译器
GCC是GNUCompilerCollection的缩写,它是世界上最为重要的开放源代码软件[18]。
因为所有其他的开放源代码项目都依赖于GCC进行编译。
比如,没有GCC,Linux的产生就
不会成为可能。
GCC能工作在很多平台上,这里所说的平台是指计算机硬件芯片和运行在其上的操作系
统的组合。
下表是GCC运行的平台。
表GCC运行的平台
硬件操作系统
AlphaRedHatLinux
HPPAHPUX
Intelx86DebianLinux,RedHatLinux,FreeBSD
MIPSIRIX
PowerPCAIX4.3.3
SparcSolaris
GCC可以编译多种语言:
C,C++,对象C(标准C的派生),Fortran,Java,Ada。
正如GCC
缩写所代表的对象一样,GCC实际上是多种编译器的统称,gcc是所有编译器的统一的程序
接口,在本书中,并没有区分GCC和gcc。
同时,GCC也能够进行代码优化,提高执行程序
的运行速度。
g++是构建于gcc基础上的C++语言编译器。
gcc编译过程分为4个阶段:
l预处理
l编译
l汇编
l连接
最简单的C语言编译的例子:
用vi建立一个文件$vi
输入字符i,插入文本以下文本
/*
*
*/
#include<>
intmain(void)
{
printf("HelloWorld!
\n");
return0;
}
最后输入字符:
wq,返回命令行,键入以下编译命令:
$gcc(-lstdc++)
如果没有错误gcc将生成默认的可执行文件,执行:
$./
HelloWorld!
$
gcc带有多达数页的编译选项,我们仅列出最常用的几项:
-o可执行文件名指定输出的可执行文件名,而不是默认的
-c只编译生成.o的目标文件,不连接生成可执行文件
-s只编译生成.s的汇编文件,不连接生成可执行文件
-g在可执行文件中加入标准调试信息
-Wall允许GCC发出警告型错误信息
选项使用的例子:
对以上使用-o,-g常用选项重新编译、执行:
$gcc-g-ohello
$./hello
GCC默认的扩展文件名:
.c
C
语言源代码
.C
.cc
C++
.i
预处理后的
C语言源代码
.ii
C++语言源代码
.S.s汇编语言源代码
.o编译后的目标代码
.a.so编译后的库代码
下面的例子由两个文件组成:
,其中,文件内容为:
intcalc(int);
intmain(intargc,char*argv[])
intiInput=0,iOutput=0;
inti=0;
scanf("%i",&iInput);
while(iInput<0)
printf("Pleaseinputapositiveinteger!
iOutput=calc(iInput);
printf("Resultis:
%i\n",iOutput);
的文件内容为:
intcalc(intiIn)
inti=0,iOut=0;
iOut=iIn;
for(i=0;i { iOut+=iOut*iIn; } returniOut; } 1、编译过程 有三种方式编译这两个源程序,一是直接使用如下命令行完成编译、链接过程: $gcc-omain 命令行中,的后缀名指明了调用c编译器,前面讲到了gcc是GCC的众多编译器的统 一入口,gcc靠后缀名决定调用什么编译器,-o参数指定了可执行文件的文件名为main。 第二种方法是编译为静态库,编译时指定静态库的位置。 需要将编译成中间文件,使用如下命令行: $gcc-c 生成静态库文件,添加到静态库中,使用如下命令行: $ar-r 命令行中,-r参数表示建立静态库,名字为。 接下来,使用如下命令行: $gcc-omain 上面这条命令也可以用下面的命令完成: $gcc-lcalc–omain -l参数可以指定库名称,这里calc表示使用库,库名字前面的lib和后面的.a被省略 掉了,遵从了命名法。 第三种方法是建立共享库,编译时指定共享库。 首先,编译为,使用命令行: $gcc-c-fpic 命令行中,-fpic指定为可重分配地址属性,pic是positionindependencecode的缩 写。 接下来使用生成共享库: $gcc-shared–o 这两条命令也可以缩减为一行: $gcc-shared-fpic-o 最后编译,链接生成的共享库: $gcc-omain 2make项目管理器 make项目管理器(GNU中的名称为gmake)可以根据项目开发者说明的项目开 发文件Makefile自动的进行编译配置和重复编译,能实现复杂项目的编译自动化。 项目开发文件Makefile的编写使用以下规则: 目标体1:依赖体1[依赖体2[...]] 命令行1 命令行2 [...] 目标体2:依赖体1[依赖体2[...]] 命令行1 命令行2 [...] [...] 其中目标体是命令行要生成的输出文件,依赖体是命令行要输入的文件或选项,命 令行序列是要创建目标体文件所需要的步骤,例如编译命令。无特别指定,make 总是使用当前目录中的Makefile进行自动编译。 例如我们在当前目录中有两个项目开发文件和,则Makefile文件可以 编写为: hello: gcc-ohello : gcc-c clean: rmhello*.o make命令的使用: $gmake 输入make或makehello将生成Makefile中所有的目标文件,即hello,,。 $gmake 将仅生成目标文件 $gmakeclean 是一条伪目标生成命令,该目标没有依赖体,它只执行对已生成目标文件的删除。当我们对 以上依赖体中的任意一个进行了修改,重新make时仅会引发对应目标体的重新生成,从而 提高了编译的效率并保证了项目开发的正确性。 3gdb程序调试器 GDB是GNUProjectDebugger的缩写,用于调试Ada,C,C++,Objective-C,Pascal和 其他语言编写的程序[20],这些程序可以运行在本地计算机上,也可以运行在远程计算机上。 GDB可以运行在几乎所有的UNIX和微软Windows平台上。 GDB主要能做下面4种事(以及由它们所支持的其他事情): 1)启动程序,指定可能影响程序运行的任何条件; 2)指定程序在一定条件下停止; 3)检查当程序停止时发生的事情; 4)通过改变程序中的某些条件,测试可能造成的软件错误,还可以由此学习其他的软 件错误。 GDB可以做源代码级别的程序调试(需要在编译时指定相应条件),也可以做二进制级 别的程序调试。 如果您在gcc编译选项中用到了-g调试选项,则编译出的可执行文件就会带有符号表。这 样的程序就可以使用gdb跟踪调试,观察到它的高级语言源代码的执行过程和变量的中间 结果,从而能快速的排除程序运行时发生的错误。以下是一个带有运行时错误的C程序,注 意程序想通过传地址方式在一个函数中为字符变量C赋一个字符,但它引用了一个空指针, 这将引发运行时的段非法错误使得程序异常终止。但我们可以通过gdb跟踪到它产生错误 的位置,从而分析出产生错误的原因。 /* * */ #include<> voidmyputc(char*cptr) { *cptr='a'; printf("myputc=%c\n",*cptr); } intmain(void) { charc; char*cptr; c='A'; myputc(cptr); return0; } 使用带-g选项的gcc编译、执行: $gcc-g-odebugmy $./debugmy 段错误 $ 使用gdb跟踪查错 $gdb./debugmy GNUgdbRedHatLinux(6.3.0. Copyright2004FreeSoftwareFoundation,Inc. GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare welcometochangeitand/ordistributecopiesofitundercertainconditions. Type"showcopying"toseetheconditions. ThereisabsolutelynowarrantyforGDB.Type"showwarranty"fordetails. ThisGDBwasconfiguredas"i386-redhat-linux-gnu"...Usinghost libthread_dblibrary "/lib/". (gdb) 现在进入了gdb调试状态,可以使用gdb的调试子命令跟踪程序的执行。Gdb常 用命令: list[行号]列出指定行号的上下行(缺省为10行) break[源程序文件名:]行号建立一个断点 run启动被调试的程序 next从断点处向下执行一行 step从断点处向下执行一行,当前行为函数则跟踪进入函数 continue继续从断点处连续执行 print变量名打印变量当前值 quit退出gdb 让我们现使用list命令查看一下要调试的程序是否已经装入,输入: (gdb)list10 5voidmyputc(char*cptr) 6{ 7*cptr='a';8printf("myputc=%c\n",*cptr);9} 10intmain(void) 11{ 12charc;13char*cptr;14c='A'; 我们将断点设在第15行上,输入: (gdb)break15 Breakpoint1at0x80483c0:file,line15. 开始跟踪执行,输入: (gdb)run Startingprogram:/root/ipc/debugmy Readingsymbolsfromsharedobjectreadfromtargetmemory...done. LoadedsystemsuppliedDSOat0xffffe000 Breakpoint1,main()at:15 15myputc(cptr); 程序执行到第 15行上停止,我们采用单步执行跟踪错误的发生,输入 :(gdb)step myputc(cptr=0x9bbe40"U\211WVS\203L\215s")at:7 7 *cptr='a';程序执行一行,进入函数myputc,再单步执行一行,再次输入: (gdb)step ProgramreceivedsignalSIGSEGV,Segmentationfault. 0x0804838dinmyputc(cptr=0x9bbe40"U\211WVS\203L\215s")at:7 7*cptr='a'; 此时gdb报告在执行改行时接受到一个段失败的信号,由此我们可以知道错误发生在该行 上,进一步我们可以推断出该错误的发生是因为指针cptr未初始化,它指向了一个非法的 地址,所以在向它指向的单元赋值时发生了段错误。
iOut+=iOut*iIn;
returniOut;
1、编译过程
有三种方式编译这两个源程序,一是直接使用如下命令行完成编译、链接过程:
$gcc-omain
命令行中,的后缀名指明了调用c编译器,前面讲到了gcc是GCC的众多编译器的统
一入口,gcc靠后缀名决定调用什么编译器,-o参数指定了可执行文件的文件名为main。
第二种方法是编译为静态库,编译时指定静态库的位置。
需要将编译成中间文件,使用如下命令行:
$gcc-c
生成静态库文件,添加到静态库中,使用如下命令行:
$ar-r
命令行中,-r参数表示建立静态库,名字为。
接下来,使用如下命令行:
上面这条命令也可以用下面的命令完成:
$gcc-lcalc–omain
-l参数可以指定库名称,这里calc表示使用库,库名字前面的lib和后面的.a被省略
掉了,遵从了命名法。
第三种方法是建立共享库,编译时指定共享库。
首先,编译为,使用命令行:
$gcc-c-fpic
命令行中,-fpic指定为可重分配地址属性,pic是positionindependencecode的缩
写。
接下来使用生成共享库:
$gcc-shared–o
这两条命令也可以缩减为一行:
$gcc-shared-fpic-o
最后编译,链接生成的共享库:
2make项目管理器
make项目管理器(GNU中的名称为gmake)可以根据项目开发者说明的项目开
发文件Makefile自动的进行编译配置和重复编译,能实现复杂项目的编译自动化。
项目开发文件Makefile的编写使用以下规则:
目标体1:
依赖体1[依赖体2[...]]
命令行1
命令行2
[...]
目标体2:
其中目标体是命令行要生成的输出文件,依赖体是命令行要输入的文件或选项,命
令行序列是要创建目标体文件所需要的步骤,例如编译命令。
无特别指定,make
总是使用当前目录中的Makefile进行自动编译。
例如我们在当前目录中有两个项目开发文件和,则Makefile文件可以
编写为:
hello:
gcc-ohello
:
gcc-c
clean:
rmhello*.o
make命令的使用:
$gmake
输入make或makehello将生成Makefile中所有的目标文件,即hello,,。
将仅生成目标文件
$gmakeclean
是一条伪目标生成命令,该目标没有依赖体,它只执行对已生成目标文件的删除。
当我们对
以上依赖体中的任意一个进行了修改,重新make时仅会引发对应目标体的重新生成,从而
提高了编译的效率并保证了项目开发的正确性。
3gdb程序调试器
GDB是GNUProjectDebugger的缩写,用于调试Ada,C,C++,Objective-C,Pascal和
其他语言编写的程序[20],这些程序可以运行在本地计算机上,也可以运行在远程计算机上。
GDB可以运行在几乎所有的UNIX和微软Windows平台上。
GDB主要能做下面4种事(以及由它们所支持的其他事情):
1)启动程序,指定可能影响程序运行的任何条件;
2)指定程序在一定条件下停止;
3)检查当程序停止时发生的事情;
4)通过改变程序中的某些条件,测试可能造成的软件错误,还可以由此学习其他的软
件错误。
GDB可以做源代码级别的程序调试(需要在编译时指定相应条件),也可以做二进制级
别的程序调试。
如果您在gcc编译选项中用到了-g调试选项,则编译出的可执行文件就会带有符号表。
这
样的程序就可以使用gdb跟踪调试,观察到它的高级语言源代码的执行过程和变量的中间
结果,从而能快速的排除程序运行时发生的错误。
以下是一个带有运行时错误的C程序,注
意程序想通过传地址方式在一个函数中为字符变量C赋一个字符,但它引用了一个空指针,
这将引发运行时的段非法错误使得程序异常终止。
但我们可以通过gdb跟踪到它产生错误
的位置,从而分析出产生错误的原因。
voidmyputc(char*cptr)
*cptr='a';
printf("myputc=%c\n",*cptr);
charc;
char*cptr;
c='A';
myputc(cptr);
使用带-g选项的gcc编译、执行:
$gcc-g-odebugmy
$./debugmy
段错误
使用gdb跟踪查错
$gdb./debugmy
GNUgdbRedHatLinux(6.3.0.
Copyright2004FreeSoftwareFoundation,Inc.
GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare
welcometochangeitand/ordistributecopiesofitundercertainconditions.
Type"showcopying"toseetheconditions.
ThereisabsolutelynowarrantyforGDB.Type"showwarranty"fordetails.
ThisGDBwasconfiguredas"i386-redhat-linux-gnu"...Usinghost
libthread_dblibrary
"/lib/".
(gdb)
现在进入了gdb调试状态,可以使用gdb的调试子命令跟踪程序的执行。
Gdb常
用命令:
list[行号]列出指定行号的上下行(缺省为10行)
break[源程序文件名:
]行号建立一个断点
run启动被调试的程序
next从断点处向下执行一行
step从断点处向下执行一行,当前行为函数则跟踪进入函数
continue继续从断点处连续执行
print变量名打印变量当前值
quit退出gdb
让我们现使用list命令查看一下要调试的程序是否已经装入,输入:
(gdb)list10
5voidmyputc(char*cptr)
6{
7
8
9
10intmain(void)
11{
12
13
14
我们将断点设在第15行上,输入:
(gdb)break15
Breakpoint1at0x80483c0:
file,line15.
开始跟踪执行,输入:
(gdb)run
Startingprogram:
/root/ipc/debugmy
Readingsymbolsfromsharedobjectreadfromtargetmemory...done.
LoadedsystemsuppliedDSOat0xffffe000
Breakpoint1,main()at:
15
15myputc(cptr);
程序执行到第
15行上停止,我们采用单步执行跟踪错误的发生,输入
(gdb)step
myputc(cptr=0x9bbe40"U\211WVS\203L\215s")at:
程序执行一行,进入函数myputc,再单步执行一行,再次输入:
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0x0804838dinmyputc(cptr=0x9bbe40"U\211WVS\203L\215s")at:
7*cptr='a';
此时gdb报告在执行改行时接受到一个段失败的信号,由此我们可以知道错误发生在该行
上,进一步我们可以推断出该错误的发生是因为指针cptr未初始化,它指向了一个非法的
地址,所以在向它指向的单元赋值时发生了段错误。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1