第 3 章 linux系统c语言开发工具

39
第 3 第 Linux 第C 第第第第第第

Upload: danika

Post on 12-Jan-2016

93 views

Category:

Documents


2 download

DESCRIPTION

第 3 章 Linux系统C语言开发工具. 本章重点. Linux 环境中将 C 程序转换成可执行文件所经历的过程和命令 gcc 、 make 、 gdb 工具的使用. 2. 3. 1 第一个 Linux C 程序. 例 3- 1 :设计一个程序, 在屏幕打印 5 行“ HELLO, LINUX WORLD” 。 步骤 1: 设计编辑源程序代码 编辑程序只需要用文本编辑器 vim ,编辑程序在终端中输出 : [root@localhost root]#vim 3- 1.c - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 3 章  Linux系统C语言开发工具

第 3 章

Linux 系统 C 语言开发工具

Page 2: 第 3 章  Linux系统C语言开发工具

22

本章重点

Linux 环境中将 C 程序转换成可执行文件所经历的过程和命令

gcc 、 make 、 gdb 工具的使用

Page 3: 第 3 章  Linux系统C语言开发工具

33

3.1 第一个 Linux C 程序 例 3-1 :设计一个程序,在屏幕打印 5 行“ HELLO, LINUX WORLD” 。

步骤 1: 设计编辑源程序代码

编辑程序只需要用文本编辑器 vim ,编辑程序在终端中输出 :[root@localhost root]#vim 3-1.c

/*3-1.c 程序:在屏幕上输出“这是第一个 Linux c 程序 !”*/ #include <stdio.h> /* 文件预处理,包含标准输入输出库 */int main () /*C 程序的主函数,开始入口 */{ int i, j; for (i=0,j=5; i < j; i++){ printf("HELLO, LINUX WORLD\n"); exit(0)}return 0;}

输入完成后存盘:按 ESC 键→输入“ :wq” 回车

Page 4: 第 3 章  Linux系统C语言开发工具

44

3.1 第一个 Linux c 程序步骤 2: 编译程序

编译程序前,最好请确认 c 源程序文件的存在,打开 Linux 终端输入“ ls” 命令,查看当前目录下是否有 3-1.c 文件 ;

输入命令 :[root@localhost root]#gcc 3-1.c ; 若编译时没有出现错误信息,说明程序编译成功。

步骤 3: 运行程序 编译好 3-1.c 程序后,默认生成的可执行文件是 a.o

ut ; 输入命令: [root@localhost root]#./a.out 此时系统会出现运行结果。

Page 5: 第 3 章  Linux系统C语言开发工具

5

3.2.1 gcc 编译器 gcc 是( GNU Cmpiler Collection 的简称),它是 GNU

项目中符合 ANSI C 标准的编译系统,能够编译用 C 、C++ 和 Object C 等语言编写的程序。

cc 命令可以启动 C 编译系统,当执行 gcc 时,它将完成预处理、编译、汇编和连接 4 个步骤并最终生成可执行代码。产生的可执行程序默认被保存为 a.out 文件。

gcc 命令可以接受多种文件类型并依据用户指定的命令行参数对它们做出相应处理。

如果 gcc 无法根据一个文件的扩展名决定它的类型,它将假定这个文件是一个目标文件或库文件。

Page 6: 第 3 章  Linux系统C语言开发工具

66

3.2.1 gcc 编译器gcc 编译流程

Page 7: 第 3 章  Linux系统C语言开发工具

77

3.2.1 gcc 编译器gcc 支持编译的一些源文件的后缀及其解释

Page 8: 第 3 章  Linux系统C语言开发工具

88

3.2.1 gcc 编译器gcc 命令语法:

gcc [ 参数 ] 要编译的文件 [ 参数 ] [ 目标文件 ]

目标文件可省略, gcc 默认生成可执行的文件为 a.out ,如果想要生成自己命名的可执行文件,通常使用“ -o” 参数。[root@localhost root]#gcc 3-1.c –o 3-1

Page 9: 第 3 章  Linux系统C语言开发工具

9

3.2.1 gcc 编译器例 3-2 :设计一个程序,要求把输入的百分制的

成绩转换成五级制输出。即输入成绩大于等于 90 分,显示“优秀”;若成绩介于 80~90 分,显示“良好”;若成绩介于 70~80 分,显示“中等”;若成绩介于 60~70 分,显示“及格”;若成绩小于 60 分,显示“不及格”。

Page 10: 第 3 章  Linux系统C语言开发工具

1010

3.2.1 gcc 编译器 步骤 1: 编辑源程序代码 [root@localhost root]#vim 3-2.c

Page 11: 第 3 章  Linux系统C语言开发工具

1111

3.2.1 gcc 编译器步骤 2: 用 gcc 编译程序

[root@localhost root]#gcc 3-2.c –o 3-2

步骤 3: 运行程序[root@localhost root]#./3-2

思考题:设计一个程序,要求输入一个数,如果此数大于 0 ,显示“输入的为正数”,否则显示“输入的为负数”。

Page 12: 第 3 章  Linux系统C语言开发工具

12

3.2.2 函数库 标准系统库文件一般存放在 linux 文件系统 /lib 和

/usr/lib 目录中。 C 语言编译器需要知道要搜索哪些库文件,默认情况下,它只搜索标准 C 语言库。

库文件必须遵循特定的命名规范并且需要在命令行中明确指定。

库文件的名字总是以 lib 开头,随后的部分指明这是什么库(例如, c 代表 C 语言库, m 代表数学库)。文件名的最后部分以 . 开始,然后给出库文件的类型: .a 代表传统的静态函数库 .so 代表共享函数库

例如 :libm.a 为静态数学函数库。

Page 13: 第 3 章  Linux系统C语言开发工具

13

3.2.2 函数库1 .静态库 静态库,也称作归档库( archive ),按惯例它们的文

件名都以 .a 结尾。比如,标准 C 语言函数库 /usr/lib/libc.a 和 X11 函数库 /usr/X11/lib/libX11.a 。

创建和维护自己的静态库 : 只要使用 ar (代表 archive ,即建立归档文件)程

序和 gcc -c 命令对函数分别进行编译。 应该尽可能把函数分别保存到不同的源文件中。如果

函数需要访问公共数据,则把它们放在同一个源文件中并使用在该文件中声明的静态变量。

Page 14: 第 3 章  Linux系统C语言开发工具

14

3.2.2 函数库 例 3.5 :创建一个小型函数库,它包含两个函数 pro1 和 pro2 ,然

后在一个示例程序中调用其中一个函数。 步骤 1 为两个函数分别创建各自的源文件(将它们分别命名为

pro1.c 和 pro2.c )。[root@localhost root]# cat pro1.c#include <sdtio.h>void pro1(int arg){

printf(“hello : %d\n”,arg) ;}

[root@localhost root]# cat pro2.c#include <sdtio.h>void pro2(char *arg){

printf(“ 您好: %s\n”,arg) ;}

Page 15: 第 3 章  Linux系统C语言开发工具

15

3.2.2 函数库 步骤 2 分别编译这两个函数,产生要包含在库文件中的目标文件

。通过调用带有 -c 选项的 gcc 编译器来实现, -c 选项的作用是阻止编译器创建一个完整的程序 ,gcc 将把源程序编译成目标程序,文件名为以 .o 结尾。如果此时试图创建一个完整的程序将不会成功,因为还未定义main 函数。[root@localhost root]# gcc -c pro1.c pro2.c[root@localhost root]# ls *.opro1.o pro2.o

步骤 3 编写一个调用 pro2 函数的程序。首先,为库文件创建一个头文件 lib.h 。这个头文件将声明库文件中的函数,它应该被所有希望使用库文件的应用程序所包含。[root@localhost root]# cat lib.h/*lib.h : pro1.c , pro2.c*/void pro1(int);void pro2(char *);

Page 16: 第 3 章  Linux系统C语言开发工具

16

3.2.2 函数库 步骤 4 主程序( program.c ),它包含库的头文件并且调用库中的

一个函数。[root@localhost root]# cat program.c#include “lib.h”int main(){

pro2(“Linux world”);exit(0);

} 步骤 5 编译并测试程序。暂时为编译器显式指定目标文件,然后

要求编译器编译的文件并将其与预先编译好的目标模块 pro2.o链接。[root@localhost root]# gcc -c program.c[root@localhost root]# gcc -o program program.o pro2.o[root@localhost root]# ./program您好: Linux world

Page 17: 第 3 章  Linux系统C语言开发工具

17

3.2.2 函数库 步骤 6 创建并使用一个库文件。用 ar 程序创建一个归档文件并将目标文件添加进去。这个程序之所以称为 ar,是因为它将若干单独的文件归并到一个大的文件中以创建归档文件。注意,也可以用 ar 程序来创建任何类型文件的归档文件。[root@localhost root]# ar crv libfoo.a pro1.o pro2.o

函数库就可使用了。

Page 18: 第 3 章  Linux系统C语言开发工具

18

3.2.2 函数库 可以在编译器命令行的文件列表中添加该库文件以创建

程序:[root@localhost root]# gcc -o program program.o libfoo.a[root@localhost root]# ./program您好: Linux world

也可以用 -l 选项来访问函数库,但是因为其未保存在标准位置,所以必须用 -L 选项来指示 gcc 在何处可以找到它:

[root@localhost root]#gcc -o program program.o -L. -lfoo -L. 选项指示编译器在当前目录” .” 中查找函数库。 -lfoo 选项指示编译器使用名为 libfoo.a 的函数库(或者名为

libfoo.so 的共享库,如果它存在的话)。

Page 19: 第 3 章  Linux系统C语言开发工具

19

3.2.2 函数库2 .共享库 静态库的一个缺点,当同时运行许多应用程序并且它们都使

用来自同一个函数库的函数时,就会在内存中有同一函数的多份拷贝,在程序文件自身中也有多份同样的拷贝。这将消耗大量宝贵的内存和磁盘空间。可以用共享库来实现函数的动态链接。

Linux 支持共享库 ( 动态链接库 ) 。共享库的保存位置与静态库是一样的,但共享库有不同的文件名后缀。在典型的Linux 系统中,标准数学库的共享库是 /usr/lib/libm.so 。

程序使用共享库时,它的链接方式是这样的:它本身不再包含函数代码,而是运行时可访问的共享代码。当编译好的程序被装载到内存中执行时,函数引用被解析并产生对共享库的调用,如果有必要共享库才被加载到内存中。

Page 20: 第 3 章  Linux系统C语言开发工具

20

3.3 make 工具Linux 有个很强大的工具 make ,它可以管理多

个模块。 make 工具提供灵活的机制来建立大型的软件项目。

make 工具依赖于一个特殊的、名字为 makefile或 Makefile 的文件,这个文件描述了系统中各个模块之间的依赖关系。

系统中部分文件改变时, make 根据这些关系决定一个需要重新编译的文件的最小集合。如果软件包括几十个源文件和多个可执行文件,这时make 工具特别有用。

Page 21: 第 3 章  Linux系统C语言开发工具

21

3.3.1 make 命令命令语法:make [ 选项 ] [ 目标 ] [宏定义 ]常用选项:

-d 显示调试信息-f 文件 告诉make 使用指定文件作为依赖关系文件。-n 不执行 makefile 中的命令,只显示输出这些命令-s 执行但不显示任何信息。

Page 22: 第 3 章  Linux系统C语言开发工具

22

3.3.2 make 规则 makefile 的默认文件名为 GNUmakefile 、 makefile 或

Makefile ,当然也可以在 make 的命令行中指定别的文件名。多数 Linux 程序员使用第三种文件名 Makefile 。

Makefile 中包含一些规则来告诉make 处理哪些文件以及如何处理这些文件。这些规则主要是描述哪些文件(称为target 目标文件,不要和编译时产生的目标文件相混淆)是从哪些别的文件(称为 dependency 依赖文件)中产生的,以及用什么命令( command )来执行这个过程。

依靠这些信息, make 会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间(称为该文件时间戳)至少比它的一个依赖文件还旧的话, make就执行相应的命令,以更新目标文件。目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。

Page 23: 第 3 章  Linux系统C语言开发工具

23

3.3.2 make 规则一个 Makefile 文件主要含有一系列的 make 规则

,每条make 规则包含以下内容:目标文件列表 : 依赖文件列表<TAB> 命令列表 目标文件列表:即 make 最终需要创建的文件,中间用空格隔开,如可执行文件和目标文件;也可以是要执行的动作。

依赖文件列表:是编译目标文件所需要的其他文件。 命令 (command)列表:是 make 执行的动作,通常是把指

定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为 TAB 字符。

除非特别指定,否则 make 的工作目录就是当前目录。

Page 24: 第 3 章  Linux系统C语言开发工具

24

3.3.2 make 规则例 3.6 : Makefile 文件实例

[root@localhost root]# cat Makefile# 一个简单的 Makefile 的例子,以 # 开头的为注释行test: prog.o code.o

gcc -o test prog.o code.o prog.o: prog.c prog.h code.h

gcc -c prog.c -o prog.o code.o: code.c code.h

gcc -c code.c -o code.o clean:

rm -f *.o

Page 25: 第 3 章  Linux系统C语言开发工具

25

3.3.2 make 规则调用 make 命令:

[root@localhost root]# make target target 是 Makefile 文件中定义的目标之一,如果省略

target , make就将生成 Makefile 文件中定义的第一个目标。

对于例 3.6 ,单独的一个“ make” 命令等价于:[root@localhost root]# make test

Page 26: 第 3 章  Linux系统C语言开发工具

26

3.3.3 Makefile 中的变量 Makefile里的变量就像一个环境变量。事实上,环境变量在 make 中也被解释成 make 的变量。这些变量对大小写敏感,一般使用大写宇母。

Makefile 中的变量是用一个字符串在 Makefile 中定义的,这个字符串就是变量的值。定义变量的语法:VARNAME=string

引用变量的值: ${VARNAME} make 解释规则时, VARNAME 在等式右端展开为定义

它的字符串。变量一般都在 Makefile 的前面部分定义。按照惯例,所

有的 Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile 的维护。

Page 27: 第 3 章  Linux系统C语言开发工具

27

3.3.3 Makefile 中的变量利用变量重写前面的 Makefile :

OBJS=prog.o code.oCC=gcc test: ${ OBJS }

${ CC } -o test ${ OBJS } prog.o: prog.c prog.h code.h

${ CC } -c prog.c -o prog.o code.o: code.c code.h

${ CC } -c code.c -o code.o clean:

rm -f *.o

Page 28: 第 3 章  Linux系统C语言开发工具

28

3.3.3 Makefile 中的变量 环境变量 : 使用方法很简单,在 make 启动时, make读取系

统当前已定义的环境变量,并且创建与之同名同值的变量,因此用户可以像在 shell 中一样在 Makefile 中方便的引用环境变量。需要注意的是,如果用户在 Makefile 中定义了同名的变量,用户自定义变量将覆盖同名的环境变量。

此外, Makefile 中还有一些预定义变量和自动变量,但是看起来并不像自定义变量那样直观。

Page 29: 第 3 章  Linux系统C语言开发工具

29

3.4 gdb 调试工具上面例子,可以简化为:

OBJS=prog.o code.o

CC=gcc

test: ${ OBJS }

${ CC } -o $@ $^

prog.o: prog.c prog.h code.h

code.o: code.c code.h

 clean:

rm -f *.o

Page 30: 第 3 章  Linux系统C语言开发工具

30

3.4 gdb 调试工具Linux 下的 gdb 调试器,是一款 GNU组织开发

并发布的 UNIX/Linux 下的程序调试工具。虽然它没有图形化的友好界面,但是它强大的功能,足以与很多商业化的集成开发工具相媲美。

在进行应用程序的调试之前,要注意的是 gdb进行调试的是可执行文件,而不是如“ .c” 这样的源代码文件。因此,需要先通过 gcc 编译生成可执行文件才能用 gdb进行调试。

Page 31: 第 3 章  Linux系统C语言开发工具

31

3.4 gdb 调试工具 命令语法: gdb [ 选项 ][ 可执行程序 [core 文件 |进程

ID]]功能:跟踪指定程序的运行,给出它的内部运行状态以协助你定位程序中的错误。你还可以指定一个程序运行错误产生的 core 文件,或者正在运行的程序进程 ID 。

常用选项:-c core 文件 使用指定 core 文件检查程序。-h 列出命令行选项的简要介绍。-n 忽略 ~/.gdbinit 文件中指定的执行命令

。-q 禁止显示介绍信息和版权信息。-s 文件 使用保存在指定文件中的符号表。

Page 32: 第 3 章  Linux系统C语言开发工具

32

3.4 gdb 调试工具 启动 gdb : 要使用 gdb 调试程序,必须使用 -g 参数重新编译该程序。此选项用于生成包含符号表和调试信息的可执行文件。程序成功编译以后,就可以使用 gdb 调试它,注意 gdb 产生的 (gdb)提示符。[root@localhost root]# gcc -g hello.c -o hello[root@localhost root]# gdb -q hello……(gdb)

启动 gdb 后,可以使用很多命令。离开 gdb :使用 quit 命令可以离开 gdb 环境并回到

shell提示符。 gdb 支持很多的命令且能实现不同的功能。 部分命令:见 P94 。

Page 33: 第 3 章  Linux系统C语言开发工具

33

3.4 gdb 调试工具 例 3.7 设计一个程序,要求输入两个整数,判断并输出其中的最小数。 步骤 1 设计编辑源程序代码。

[root@localhost root]#vim 3-7.c

Page 34: 第 3 章  Linux系统C语言开发工具

34

3.4 gdb 调试工具步骤 2 用 gcc 编译程序。

在编译的时候要加上选项“ -g” 。这样编译出的可执行代码中才包含调试信息,否则之后 gdb 无法载入该可执行文件。

[root@localhost root]# gcc 3-7.c -o 3-7 -g

步骤 3 进入 gdb 调试环境。gdb进行调试的是可执行文件,因此要调试的是 3-7而不是 3-7.c ,输入如下:

[root@localhost root]#gdb 3-7回车后就进入了 gdb 调试模式。

Page 35: 第 3 章  Linux系统C语言开发工具

35

3.4 gdb 调试工具 步骤 4 用 gdb 调试程序。

( 1 )查看源文件 在 gdb 中输入“ l”(list)就可以查看程序源代码,一次显示 10 行。

( 2 )设置断点 在 gdb 中设置断点命令是“ b”(break) ,后面跟行号或者函数名。

( 3 )查看断点信息 用命令“ info b”(info break) 查看断点信息。

( 4 )运行程序 输入“ r”(run) 开始运行程序。

( 5 )查看与设置变量值 程序运行到断点处会自动暂停,输入“ p变量名”可查看指定变量的值。

( 6 )单步运行 在断点处输入 “ n”(next) 或者“ s”(step) 可单步运行。它们之间的区别在

于:若有函数,调用时,“ s” 会进入该函数,而“ n” 不会进入该函数。

Page 36: 第 3 章  Linux系统C语言开发工具

36

3.4 gdb 调试工具步骤 4 用 gdb 调试程序。( 7 )继续运行程序

在查看完变量或堆栈情况后可以输入“ c”(continue)命令恢复程序的正常运行,把剩余的程序执行完,并显示执行结果。

( 8 )退出 gdb 环境退出 gdb 环境只要输入“ q”(quit) 命令,回车后退出

gdb 环境。

Page 37: 第 3 章  Linux系统C语言开发工具

3737

思考与实验1. 编写一个简单的 C 语言程序:输出两行文字“ How are you” ,

在 Linux 下编辑、编译、运行。2. 编写一个简单的 C 语言程序:根据输入的两个整数求平均值并且

在终端输出,通过 gcc 编译器得到它的汇编程序文件。3. Makfile 文件中的每一行是描述文件间依赖关系的 make 规则。

对于下面的 Makefile 文件 :CC = gccOPTIONS = -O3 -oOBJECTS = main.o stack.o misc.oSOURCES = main.c stack.c misc.cHEADERS = main.h stack.h misc.hpolish: main.c $(OPJECTS)

$(CC) $(OPTIONS) power $(OBJECTS) -lmmain.o: main.c main.h misc.hstack.o: stack.c stack.h misc.hmisc.o: misc.c misc.h

回答:a. 所有变量名字b. 所有目标文件的名字c. 每个目标的依赖文件d. 生成每个目标文件所需执行的命令e. 画出 makefile 对应的依赖关系树。f. 生成 main.o stack.o 和misc.o 时会执行哪些命令,为什么?

Page 38: 第 3 章  Linux系统C语言开发工具

38

思考与实验4. 用编辑器创建 main.c, compute.c, input.c,

compute.h, input.h 和 main.h 文件。下面是它们的内容。注意 compute.h 和 input.h 文件仅包含了 compute 和 input 函数的声明但没有定义。定义部分是在 compute.c 和 input.c 文件中。 main.c 包含的是两条显示给用户的提示信息。

Page 39: 第 3 章  Linux系统C语言开发工具

39

5. 下面程序的功能是提示你输入一个整数并把它显示到屏幕上,现在它能够通过编译但运行不正常。利用 gdb找出它的错误并改正它。重新编译和运行改过的程序以确保它工作正常。

#include<stdio.h>#define PROMPT " 请输入一个整数: "void get_input(char *, int *);void main(){

int *user_input;get_input(PROMPT, user_input);(void) printf("你输入了: %d 。 \n", user_input);

}void get_input(char *prompt, int *ival){

(void) printf("%s", prompt);scanf("%d", ival);

}