目录
1 makefile
1.1 makefile的基本规则
1.2 makefile工作原理
基本原则:
1.3 makefile中的变量
普通变量
自动变量
模式规则
1.4 makefile函数
1.5 makefile的清理操作
2 gdb调试
2.1 gdb介绍
2.2 生成调试信息
2.3 启动gdb
2.4 显示源代码
2.5 设置断点
简单断点—当前文件
多文件设置断点---其他文件
查询所有断点
条件断点
维护断点
2.6 调试代码
2.7 查看变量的值
查看运行时变量的值
自动显示变量的值
查看修改变量的值
3文件IO
3.1 C库IO函数的工作流程
3.2 C库函数与系统函数的关系
3.3 虚拟地址空间
3.4 pcb和文件描述符表
makefile文件中定义了一系列的规则来指定, 哪些文件需要先编译, 哪些文件需要后编译, 哪些文件需要重新编译, 甚至于进行更复杂的功能操作, 因为makefile就像一个Shell脚本一样, 其中也可以执行操作系统的命令. makefile带来的好处就是——“自动化编译”, 一旦写好, 只需要一个make命令, 整个工程完全自动编译, 极大的提高了软件开发的效率.
make是一个命令工具, 是一个解释makefile中指令的命令工具, 一般来说, 大多数的IDE都有这个命令, 比如:Visual C++的nmake, Linux下GNU的make. 可见, makefile都成为了一种在工程方面的编译方法.
makefile文件中会使用gcc编译器对源代码进行编译, 最终生成可执行文件或者是库文件.
makefile文件的命名:makefile或者Makefile
makefile由一组规则组成,规则如下:
目标: 依赖
(tab)命令
makefile基本规则三要素:
下面以具体的例子来讲解:
当前目录下有main.c fun1.c fun2.c sum.c, 根据这个基本规则编写一个简单的makefile文件, 生成可执行文件main.
第一个版本的makefile:
缺点: 效率低, 修改一个文件, 所有的文件会全部重新编译.
如果有规则用来生成该依赖文件, 则执行规则中的命令生成依赖文件;
如果没有规则用来生成该依赖文件, 则报错.
总结:
第二个版本:
缺点: 冗余, 若.c文件数量很多, 编写起来比较麻烦.
在makefile中使用变量有点类似于C语言中的宏定义, 使用该变量相当于内容替换, 使用变量可以使makefile易于维护, 修改起来变得简单。
makefile有三种类型的变量:
如:下面是变量的定义和使用
foo = abc // 定义变量并赋值
bar = $(foo) // 使用变量, $(变量名)
定义了两个变量: foo、bar, 其中bar的值是foo变量值的引用。
除了使用用户自定义变量, makefile中也提供了一些变量(变量名大写)供用户直接使用, 我们可以直接对其进行赋值:
CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项 -I
CFLAGS: C编译器的选项 -Wall -g -c
LDFLAGS : 链接器选项 -L -l
特别注意:自动变量只能在规则的命令中使用.
至少在规则的目标定义中要包含’%’, ‘%’表示一个或多个, 在依赖条件中同样可以使用’%’, 依赖条件中的’%’的取值取决于其目标:
比如: main.o:main.c fun1.o: fun1.c fun2.o:fun2.c, 说的简单点就是: xxx.o:xxx.c
makefile的第三个版本:
makefile中的函数有很多, 在这里给大家介绍两个最常用的。
src=$(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
在makefile中所有的函数都是有返回值的。
当前目录下有main.c fun1.c fun2.c sum.c
src=$(wildcard *.c) 等价于src=main.c fun1.c fun2.c sum.c
obj=$(patsubst %.c,%.o, $(src))等价于obj=main.o fun1.o fun2.o sum.o
makefile的第四个版本:
缺点: 每次重新编译都需要手工清理中间.o文件和最终目标文件
用途: 清除编译生成的中间.o文件和最终目标文件
make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令, 解决方案:
.PHONY:clean
rm -f: 强制执行, 比如若要删除的文件不存在使用-f不会报错
– make 默认执行第一个出现的目标, 可通过make dest指定要执行的目标
– make -f : -f执行一个makefile文件名称, 使用make执行指定的makefile: make -f mainmak
makefile的第5个版本:
在makefile的第5个版本中, 综合使用了变量, 函数, 模式规则和清理命令,
是一个比较完善的版本.
GDB(GNU Debugger)是GCC的调试工具。其功能强大, 现描述如下:
GDB主要帮忙你完成下面四个方面的功能:
一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序, 首先在编译时, 我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:
gcc -g hello.c -o hello
如果没有-g, 你将看不见程序的函数名、变量名, 所代替的全是运行时的内存地址。当你用-g把调试信息加入之后, 并成功编译目标代码以后, 让我们来看看如何用gdb来调试他。
program 也就是你的执行文件, 一般在当前目录下。
GDB 可以打印出所调试程序的源代码, 当然, 在程序编译时一定要加上-g的参数, 把源程序信息编译到执行文件中。不然就看不到源程序了。当程序停下来以后, GDB会报告程序停在了那个文件的第几行上。你可以用list命令来打印程序的源代码, 默认打印10行, list命令的用法如下所示:
一般是打印当前行的上5行和下5行, 如果显示函数是是上2行下8行, 默认是10行, 当然, 你也可以定制显示的范围, 使用下面命令可以设置一次显示源程序的行数。
一般来说, 为断点设置一个条件, 我们使用if关键词, 后面跟其断点条件。设置一个条件断点:
b test.c:8 if intValue == 5
如果什么都不指定, 表示disable所有的停止点。
如果什么都不指定, 表示enable所有的停止点。
如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
print 打印变量、字符串、表达式等的值, 可简写为p
p count -----打印count的值
你可以设置一些自动显示的变量, 当程序停住时, 或是在你单步跟踪时, 这些变量会自动显示。相关的GDB命令是display。
删除某个自动显示: undisplay num 或者delete display num
删除多个: delete display num1 num2
删除一个范围: delete display m-n
5. disable display dnums…
使一个自动显示无效: disable display num
使多个自动显示无效: delete display num1 num2
使一个范围的自动显示无效: delete display m-n
type = double
$4 = 13
你可以使用set var命令来告诉GDB, width不是你GDB的参数, 而是程序的变量名, 如:
set var width=47 // 将变量var值设置为47
在你改变程序变量取值时, 最好都使用set var格式的GDB命令。
从本章开始学习各种Linux系统函数, 这些函数的用法必须结合Linux内核的工作原理来理解, 因为系统函数正是内核提供给应用程序的接口, 而要理解内核的工作原理, 必须熟练掌握C语言, 因为内核也是用C语言写的, 我们在描述内核工作原理时必然要用“指针”、“结构体”、“链表”这些名词来组织语言, 就像只有掌握了英语才能看懂英文书一样, 只有学好了C语言才能看懂我描述的内核工作原理。
c语言操作文件相关问题:
使用fopen函数打开一个文件, 返回一个FILE* fp, 这个指针指向的结构体有三个重要的成员.
备注:
义中有一个_fileno成员, 这个就是文件描述符
系统调用: 由操作系统实现并提供给外部应用程序的编程接口,
(Application Programming Interface, API), 是应用程序同系统之间数据交互的桥梁.
进程的虚拟地址空间分为用户区和内核区, 其中内核区是受保护的, 用户是不能够对其进行读写操作的;
内核区中很重要的一个就是进程管理, 进程管理中有一个区域就是PCB(本质是一个结构体);
PCB中有文件描述符表, 文件描述符表中存放着打开的文件描述符, 涉及到文件的IO操作都会用到这个文件描述符.
备注:
pcb:结构体:task_stuct, 该结构体在:
/usr/src/linux-headers-4.4.0-97/include/linux/sched.h:1390
一个进程有一个文件描述符表:1024
虚拟地址空间à内核区àPCBà文件描述表à文件描述符à文件IO操作使用文件描述符