嵌入式成长轨迹14 【嵌入式环境及基础】【Linux下的C编程 上】【gcc、gdb和GNU Make】
这一模块中,c语言基础,指针、函数及自定义数据类型,数据结构,文本编辑器这几块已经学习过,这些就不再提及,就分别列举一些面试题:
·c语言基础
常见面试题1:下面的两种if语句判断方式,哪种写法更好?为什么?
if (n == 10)
if (10 == n)
常见面试题2:下面的两个定义有何区别?
const int MAX_NUM = 10;
#define MAX_NUM 10
·数据结构
常见面试题1:栈和队列的主要差别是什么?
常见面试题2:编写一个函数,实现双链表中指定节点的删除操作。
·文本编辑器
常见面试题1:vi编辑器有哪几种工作模式?
常见面试题2:使用vi编辑器编写源代码文件时,如何进行关键字的补全?
常见面试题3:在emacs编辑器中,保存文件的命令有哪些?
一、gcc
GCC(GNU Compiler Collection)是一套功能强大、性能优越的编程语言编译器,它是GNU计划的代表作品之一。GCC以GPL和LGPL许可证发行,它是类Unix和苹果电脑Mac OS X操作系统的标准编译器。
1 基本选项
-E 只做预处理
-S 只做预处理和编译
-c 只做预处理、编译和汇编
-o file 指定输出文件为file
2 警告选项
1)说明
在编译程序的过程中,编译器的报错和警告信息对于程序员来说是非常重要的。GCC包含了完整的出错检查和警告提示功能,它们可以帮助Linux程序员尽快找到错误的或潜在的错误代码,从而写出更加专业和优美的代码
2)选项
-Wall 启用所有警告信息
-Werror 发生警告时取消编译操作,也即将警告当做错误
-w 禁用所有警告信息
3 优化选项
GCC具有优化代码的功能,主要的优化选项包括:
-O0:不进行优化处理;
-O或-O1:进行基本的优化,这些优化在大多数情况下都会使程序执行得更快
-O2:除了完成-O1级别的优化外,还要一些额外的调整工作,如处理器指令调度等,这是GNU发布软件的默认优化级别;
-O3:除了完成-O2级别的优化外,还进行循环的展开以及其它一些与处理器特性相关的优化工作;
-Os:生成最小的可执行文件,主要用在嵌入式领域。
4 连接器选项
-Idirectory 向GCC的头文件搜索路径中添加新的目录
-Ldirectory 向GCC的库文件搜索路径中添加新的目录
-llibrary 提示连接程序在创建可执行文件时包含指定的库文件
-static 强制使用静态链接库
-shared 生成动态库文件
库文件可分为静态库和动态库。
静态库是指编译连接时,将库文件的代码全部加入到可执行文件中,这样运行时就不需要库文件了。静态库的后缀名一般为“.a”。
动态库是指在编译连接时并不将库文件的代码加入到可执行文件中,而是在程序执行时由运行时连接文件加载库文件,这样可以节省系统的开销。动态库的后缀名一般为“.so”。
例如我们编译是用-I选项来指定头文件的路径:
$ gcc example.c –o example –I/home/xxx/include
头文件所对应的库文件,如果没有特别指定时,GCC会到默认的搜索路径进行查找。
使用-L选项来指定库文件的路径,例如:
$ gcc example.c –o example –L/home/xxx/lib
GCC编译器在默认情况下使用动态库,但如果使用了-static选项,连接器将忽略动态库,强制使用静态链接库,即使用如下命令:
$ gcc example.c –o example –static –lm
此时静态库文件中的代码全部包含到可执行文件中,所以生成的可执行文件比较大。
5 其它选项
-x language 指定输入文件的编程语言
-v 显示编译器的版本号
-g 获得有关调试程序的详细信息
-ansi 支持符合ANSI标准的c程序
常见面试题1:GCC对程序进行编译连接时使用的是动态库还是静态库,如何进行指定?
常见面试题2:GCC编译器具有优化代码的功能,主要包括哪些优化选项,最常用的是哪个选项?
二、gdb
同GCC编译器一样,GDB(GNU Debugger)也是由GNU计划完成的、受通用公共许可证(GPL)保护的自由软件。GDB是一个功能强大的交互式程序调试工具,主要工作在字符模式下。
GDB调试器有很多命令,从简单的文件载入、断点设置,到复杂的内存查看、信号捕捉等。
在使用GDB调试程序之前,必须使用-g选项编译源文件,以便将调试信息加入到要调试的程序之中,而且-g选项不能和优化选项一起使用。
1、断点设置与管理
断点设置即在调试的程序中设置断点,断点管理包括查看断点信息、删除或禁用断点等。
1).设置断点(break)
2).查看断点信息(info break)
3).删除指定的断点(d)
4).删除指定行上的断点(clear)
5).禁用指定的断点(disable)
6).恢复指定的断点(enable)
7).设置观察点(watch)
2、数据显示与变量赋值
上面介绍了如何在程序中设置和管理断点,但只有断点没有用,要跟踪程序的运行,必须能在断点处查看或修改变量的值。
1).显示变量或表达式的值(print)
2).自动显示变量或表达式的值(display)
3).显示变量的数据类型(whatis、ptype)
4).修改变量的值(set)
3、程序执行与函数调用
上面已经介绍了run命令和continue命令,接下来介绍程序执行相关的另外一些常用命令,以及函数调用的命令。
1).单步执行(step、next)
2).退出被调用的函数(return)
3).执行到指定行(until)
4).跳转执行(jump)
5).强制调用函数(call)
4、其他常用命令
GDB的命令很多,除了上面介绍的断点设置、数据显示、程序执行等,还有一些命令比较常用,下面分别介绍。
1)查看堆栈信息(backtrace、frame)
2)查看源程序信息(info source)
3)查看寄存器(info registers)
4)查看程序的汇编代码(disassemble)
5、其它调试工具
GDB是基于字符界面的,Linux系统下还有一些基于图形界面的调试工具,如KDBG、XXGDB以及DDD等。用户只需要单击菜单或按钮即可完成程序的调试,而不需要输入命令。其实这些工具都是GDB的一层外壳,都保留着GDB的各种特性。
常见面试题1:GDB的主要功能是什么?
常见面试题2:使用GDB调试程序时,如何设置断点?
三、GNU Make
GNU Make工具的作用就是实现上面编译连接过程的自动化。它定义了一种语言,用来描述源文件、目标文件以及可执行文件之间的关系,通过检查文件的时间戳来决定程序中哪些文件需要重新编译,并发送相应的命令
1、基本规则
Makefile文件的作用是告诉Make工具做什么,多数情况是如何编译连接一个程序。
目标 : 依赖
<tab>命令
如:
example : sort.o compute.o main.o
gcc sort.o compute.o main.o -o example
sort.o : sort.c lib1.h
gcc -c sort.c -o sort.o
compute.o : compute.c
gcc -c compute.c -o compute.o
main.o : main.c lib2.h
gcc -c main.c -o main.o
2、变量的定义与使用
1).递归展开式变量
A = $(B)
B = $(C)
C = Hello
$(A)
2).直接展开式变量
A = Hello
B = $(A) World
A := Hi
其中
B := Hello World
A := Hi
B = $(A) World
A = Hi
其中
B := World
A := Hi
3、隐含规则
隐含规则是系统或用户预先定义好的一些特殊规则,主要是一些常用的依赖关系和更新命令。
.c :
$(CC) $(CFLAGS) -o $@ $<
.c .o :
$(CC) $(CFLAGS) -c $<
objects = sort.o compute.o main.o
CC = gcc
CFLAGS = -Wall -g
example : $(objects)
$(CC) $^ -o $@
sort.o : lib1.h
main.o : lib2.h
4、伪目标
Makefile文件中的目标分为两类:实目标和伪目标。实目标是真正要生成的以文件形式存放在磁盘上的目标,我们前面定义的目标都属于实目标;而伪目标则不要求生成实际的文件,它主要用于完成一些辅助性操作。
clean :
rm example $(objects)
make clean
.PHONY : clean
clean :
rm example $(objects)
5、函数
GNU Make中提供了很多函数,可以在Makefile文件中调用这些函数来进行文件名、变量以及命令等的处理。函数的调用方式与变量类似,使用“$”符号
1).patsubst函数,对字符串进行替换和分析
$(patsubst pattern,replacement,text)
$(patsubst %.c, %.o, sort.c compute.c main.c)
sort.o compute.o main.o
$(var:suffix = replacement)
$(patsubst %suffix, %replacement, $(var))
2).dir函数 获取路径
$(dir filename ... )
$(dir main.c)
./
3).notdir 函数 抽取字符串中除了路径外其他字符,也就是文件名
$(notdir filename ... )
$(notdir /home/yanyb/LinuxC/make/main.c ./Makefile)
main.c Makefile
4).suffix函数 获取文件名后缀
$(suffix filename ... )
$(suffix ./main.c)
.c
6、通用Makefile文件
下面给出的是一个通用的Makefile文件,其作者是英国的Gorge Foot,之所以说它是通用的,主要是它不需要修改就可以应用于大部分的项目之中。
1 ######################################
2 #
3 # Generic makefile
4 #
5 # by George Foot
6 # email: george.foot@merton.ox.ac.uk
7 #
8 # Copyright (c) 1997 George Foot
9 # All rights reserved.
10 #
11 # No warranty, no liability;
12 # you use this at your own risk.
13 #
14 # You are free to modify and
15 # distribute this without giving
16 # credit to the original author.
17 #
18 ######################################
19 #
20 # Customizing
21 #
22 # Adjust the following if necessary; EXECUTABLE is the target
23 # executable’s filename, and LIBS is a list of libraries to link in
24 # (e.g. alleg, stdcx, iostr, etc). You can override these on make’s
25 # command line of course, if you prefer to do it that way.
26
27 # EXECUTABLE为目标的可执行文件名,LIBS为需要连接的程序包列表,可以根据具体的项目对其进行修改。
28 #
29 EXECUTABLE := example
30 LIBS := xxx
31
32 # Now alter any implicit rules’ variables if you like, e.g.:
33 # 修改隐含规则中宏。
34 CC := gcc
35 CFLAGS := -Wall -O2 -MD
36
37 # You shouldn’t need to change anything below this point.
38 # 下面内容基本上不需要修改。
39 # 列出工作目录下所有以“.c”结尾的文件,以空格分隔,将文件列表赋给变量SOURCE
40 SOURCE := $(wildcard *.c)
41 # 调用patsubst函数,生成与源文件对应的“.o”文件列表。
42 OBJS := $(patsubst %.c, %.o, $(SOURCE))
43 # 调用patsubst函数,生成与源文件对应的“.d”文件列表,关于“.d”文件后面会给出说明。
44 DEPS := $(patsubst %.o, %.d, $(OBJS))
45 # 对DEPS列表进行处理,删除所有已经存在的项目。
46 # 这里使用的函数为filter-out,该函数使用两个用空格分割的列表作为参数,其功能是删除第2个列表中所有
47 # 存在于第1列表的项目。
48 MISSING_DEPS := $(filter-out $(wildcard $(DEPS)), $(DEPS))
49 MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d, %.c, $(MISSING_DEPS)))
50 # 声明伪目标。
51 .PHONY : everything deps objs clean veryclean rebuild
52 # 更新可执行程序,并且为每一个源文件生成或更新一个“.o”文件和一个“.d”文件。
53 everything : $(EXECUTABLE)
54 # 为每一个源文件生成或更新一个“.d”文件。
55 deps : $(DEPS)
56 # 为每一个源文件生成或更新一个一个“.o”文件和一个“.d”文件。
57 objs : $(OBJS)
58 # 删除所有“.o”文件和“.d”文件。
59 # 命令前的“@”符号表示在执行make命令的时候,不显示这条命令。
60 clean :
61 @rm -f *.o
62 @rm -f *.d
63 # 完全删除,首先执行clean,然后再删除可执行文件。
64 veryclean : clean
65 @rm -f $(EXECUTABLE)
66 # 完全重建,首先执行veryclean,然后执行everything。
67 rebuild : veryclean everything
68 # Makefile文件中的条件语句。
69 ifneq ($(MISSING_DEPS),)
70 $(MISSING_DEPS) :
71 @rm -f $(patsubst %.d,%.o,$@)
72 endif
73 -include $(DEPS)
74
75 # addprefix函数包含两个参数:文件前缀和列表,其功能是给文件列表的每一项添加一个前缀。
76 $(EXECUTABLE) : $(OBJS)
77 gcc -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))
7、GNU Automake简介
总的来说,书写Makefile文件还是比较复杂的,而且还容易出现各种错误。为了减轻程序开发人员维护Makefile文件的负担,GNU提供了一个自动生成Makefile文件的工具,即GNU Automake工具。
1).创建目录并编辑源文件
2).生成并编辑configure.in文件
3).生成aclocal.m4和configure文件
4).生成config.h.in文件
5).创建Makefile.am文件
6).生成Makefile.in文件
7).生成Makefile
常见面试题1:Makefile文件的作用是什么?
常见面试题2:简述使用Automake工具生成Makefile文件的一般步骤。