我们就先做个tree 模块吧,这里说下讲TREE的理由,很简单,如下
1、tree相对复杂点,我就说个堆栈,恐怕可以展开的东西不多。
2、正在把文件生命周期管理的中间件进行开源。正好用tree开刀。
3、tree好啊,文件夹里大把天然的测试数据,我省得造数据的麻烦了。
4、不是菜鸟经常被别人说“去看内核源码”,那好吧,既然你们总被喷,不如咱们也从tree展开,等到最后,听完,也算对linux内核的vfs有所了解。野鬼不带新手逛点带彩的地方,怎么能算“成年”呢。你不自个逛那是因为你太害羞而已。
这里谈一下tree的数据结构的一些基本特性。也就是啥是树。图论书籍中有非常科学严谨的解释。我这弱智的说说。什么算是一个树。
1、一群个体,相互有血缘关系。血缘关系只有一种,父子关系。
2、任何一个个体,只有一个老爸,且必须要有个老爸。
就这么简单。有人说你胡扯,树的根,他就没有老爸。哈。不妨我反驳你,首先,树有个性质,从图论中说。就是加上任意条边,则构成环。当然自己指向自己的边 这个不能算。因为这不是个朴素的图。如果自己指向自己的也算边,你的图可平面时,你就无法使用平面图上很多理论。
我的定义:朴素图是,边是特指连接两个不同的顶点。就是说关系,仅指两个不同的个体之间的关联。
如果这么说,那么对于一个树而言,只存在一个根的时候,就麻烦了。怎么加边呢?
所以对于树而言,理论上是不存在只有一个顶点的情况。即便就是一个根,自然会出现两个顶点。只不过根指向一个没有任何意义的顶点,如同我们编写代码是,指针指向0,表示没有意义,但不代表这个0不存在。
废话不多,我们开始上代码。不过上之前允许我再废话一下。我们要建目录了。执行如下命令:
如下编辑
保存退出,若问这是啥,别废话,敲你的键盘。
如下编辑
保存退出
如下编辑
保存退出
如下编辑
保存退出//这里的makefile仍然弱智版的,我们不进化,一个章节只谈一个方向的问题。以后专门进化。
看看出来啥东西。
OK。收工!!!
但起名字很关键。你要注意到make 里 bin/test的操作(还好是弱智版的,我要增加变量,就难解释了),这里有个 -Lbin ,这个意思是增加指定的库所在的路径。但这个-L只对-l(小写的L)有影响。 -l有什么用呢?和-Lbin组合起来就等于 bin/lib,他会把库文件前面 lib的前缀自动省去,同时某默认对.a文件而言,.a不需要书写,简化你的工作。当然你可以如下做
这看起来很微软。其实无所谓。但是你对这个.a的使用,得如下
你需要给出全名。你可以试下
肯定不对啦。如果 bin/真有个ds_tree的文件怎么办?
估计有新手会说了,bin/ds_tree.a 明显比-Lbin -lds_tree 要少,我毛病要用你的-L -l的方式啊,还要在确保库是以lib打头的,如ds_tree的库为 libds_tree.a
哦。我没有意见,但你别忘了,每个库文件都有路径,每个库文件都有 .a要明确写出来。如果你有10个库文件,貌似 -L -l就更快了。这些先进的玩意是给大工程用的,如果你偏要用自己的库文件名的话,我没意见,反正(弱智版嘛)。
2、在ds_tree.c和Makefile里都有一些错误操作。你可以试试,体会下gcc的命令的原理。
3、对比下这个Makefile和前面的Makefile有什么不同了。显然不是少了 build all。为什么不把test,放在第一个。
4、哦,对了,最后说一下,最后的正确执行结果就是 啥结果都没有 。不用吐,现在吐光了,后面还有更值得你要吐血的。
1、tree相对复杂点,我就说个堆栈,恐怕可以展开的东西不多。
2、正在把文件生命周期管理的中间件进行开源。正好用tree开刀。
3、tree好啊,文件夹里大把天然的测试数据,我省得造数据的麻烦了。
4、不是菜鸟经常被别人说“去看内核源码”,那好吧,既然你们总被喷,不如咱们也从tree展开,等到最后,听完,也算对linux内核的vfs有所了解。野鬼不带新手逛点带彩的地方,怎么能算“成年”呢。你不自个逛那是因为你太害羞而已。
这里谈一下tree的数据结构的一些基本特性。也就是啥是树。图论书籍中有非常科学严谨的解释。我这弱智的说说。什么算是一个树。
1、一群个体,相互有血缘关系。血缘关系只有一种,父子关系。
2、任何一个个体,只有一个老爸,且必须要有个老爸。
就这么简单。有人说你胡扯,树的根,他就没有老爸。哈。不妨我反驳你,首先,树有个性质,从图论中说。就是加上任意条边,则构成环。当然自己指向自己的边 这个不能算。因为这不是个朴素的图。如果自己指向自己的也算边,你的图可平面时,你就无法使用平面图上很多理论。
我的定义:朴素图是,边是特指连接两个不同的顶点。就是说关系,仅指两个不同的个体之间的关联。
如果这么说,那么对于一个树而言,只存在一个根的时候,就麻烦了。怎么加边呢?
所以对于树而言,理论上是不存在只有一个顶点的情况。即便就是一个根,自然会出现两个顶点。只不过根指向一个没有任何意义的顶点,如同我们编写代码是,指针指向0,表示没有意义,但不代表这个0不存在。
废话不多,我们开始上代码。不过上之前允许我再废话一下。我们要建目录了。执行如下命令:
1 | $ mkdir data_struct |
2 | $ cd data_struct |
3 | $ mkdir inc |
4 | $ mkdir src |
5 | $ mkdir bin |
6 | $ mkdir obj |
为什么是data_struct,模块化的思想啦,很多结构,结构套结构的。我一层层的包起来,当面向对象啊?所以干脆data_struct库吧。以后涉及抽象数据结构的,都装里面。当然为了说明学习C而涉及。如果linux下有类似模块,我们本着 绝不重复开发的原则,还是坚持用别人已经开放的模块使用。
1 | $ cd src |
2 | $:>ds_tree.c |
3 | $scribes ds_tree.c //为啥用这个名字,还好还好,google一下这个名字没有太多信息,省得与其他库C文件名冲突 |
01 | /*************** |
02 | src/ds_tree.c |
03 | by luckystar |
04 | ***************/ |
05 | static int ds_tree_flag =0; |
06 |
07 | void ds_tree_init( void ){ |
08 | if (ds_tree_flag) { |
09 | //log("module inited..",X); |
10 | return ; |
11 | } |
12 | ds_tree_flag = 1; |
13 | //todo:module init... |
14 |
15 | } |
16 |
17 | void ds_tree_destory( void ){ |
18 | if (!ds_tree_flag) { |
19 | //log("module not inited..",X); |
20 | return ; |
21 | } |
22 | ds_tree_flag = 0; |
23 | //todo:module destory... |
24 |
25 | } |
1 | $ cd ..\inc |
2 | $:>ds_tree.h |
3 | $sciribes ds_tree.h |
01 | #ifndef _ds_tree_H_ |
02 | #define _ds_tree_H_ |
03 |
04 | //ins_inc_file |
05 |
06 | //ins_typedef_def |
07 |
08 | //ins_def |
09 |
10 | //ins_func_declare |
11 |
12 |
13 | #endif //_ds_tree_H_ |
1 | $ cd ..\src |
2 | $:>ds_tree.c |
3 | $scribes test_ds_tree_main.c //只是测试代码以后不用 |
1 | #include <stdio.h> |
2 | #include "ds_tree.h" |
3 | //extern void ds_tree_init(void); //你可以尝试打开这个注释,看有什么变化,回答没有 |
4 | int main(int argc,char*argv[]){ |
5 | ds_tree_init(); |
6 | ds_tree_destory(); |
7 | return 0; |
8 | } |
1 | $ cd .. |
2 | $:>Makefile |
3 | $scribes Makefile |
01 | .PNONY:build_lib |
02 | build_lib:bin/libds_tree.a |
03 | bin/libds_tree.a:obj/ds_tree.o |
04 | ar -r bin/libds_tree.a obj/ds_tree.o |
05 | obj/ds_tree.o:src/ds_tree.c inc/ds_tree.h |
06 | gcc -fpic -Iinc -c src/ds_tree.c -o obj/ds_tree.o |
07 | |
08 | .PNONY: test |
09 | test :bin/ test |
10 | bin/ test :bin/libds_tree.a obj/test_ds_tree_main.o |
11 | gcc obj/test_ds_tree_main.o -Lbin -lds_tree -o bin/ test |
12 | #test |
13 | # gcc -Lbin -lds_tree obj/test_ds_tree_main.o -o bin/test |
14 | # you will not found func |
15 | obj/test_ds_tree_main.o:src/test_ds_tree_main.c inc/ds_tree.h |
16 | gcc -Iinc -c src/test_ds_tree_main.c -o obj/test_ds_tree_main.o |
17 | |
18 | .PNONY:clean |
19 | clean: |
20 | - rm obj/*.o |
21 | - rm bin/* |
1 | $ make test |
2 | $./bin/ test |
看看出来啥东西。
OK。收工!!!
估计有人要扁我了。"这和tree有个毛关系啊。啥代码都没有。"
我的回答很简单。你如果是新手,记得上面的每个步骤,和第一次编译前,做且仅做的内容。那上面的事情都是啥?
这叫“搭窝”,只有make过了,可以执行了,才表示你可以开发了。便便还要找蹲坑,找呢,当然我是说大的。记得第一次编译前,只做这么多。这叫"缩小开发反馈环大法"
由于咱们第一次讲linux下编写C程序,是和tree没关系,但和编写代码有关系。所以收工。当然收工前,提醒一下,关注以下内容并收集资料。
1、ar 命令,是用于将多个obj文件,归档到一个.a,也就是通常说的静态库的。但起名字很关键。你要注意到make 里 bin/test的操作(还好是弱智版的,我要增加变量,就难解释了),这里有个 -Lbin ,这个意思是增加指定的库所在的路径。但这个-L只对-l(小写的L)有影响。 -l有什么用呢?和-Lbin组合起来就等于 bin/lib,他会把库文件前面 lib的前缀自动省去,同时某默认对.a文件而言,.a不需要书写,简化你的工作。当然你可以如下做
1 | ar -r bin/ds_tree.a obj/ds_tree.o |
1 | gcc obj/test_ds_tree_main.o bin/ds_tree.a -o bin/ test |
1 | gcc obj/test_ds_tree_main.o bin/ds_tree -o bin/ test |
估计有新手会说了,bin/ds_tree.a 明显比-Lbin -lds_tree 要少,我毛病要用你的-L -l的方式啊,还要在确保库是以lib打头的,如ds_tree的库为 libds_tree.a
哦。我没有意见,但你别忘了,每个库文件都有路径,每个库文件都有 .a要明确写出来。如果你有10个库文件,貌似 -L -l就更快了。这些先进的玩意是给大工程用的,如果你偏要用自己的库文件名的话,我没意见,反正(弱智版嘛)。
2、在ds_tree.c和Makefile里都有一些错误操作。你可以试试,体会下gcc的命令的原理。
3、对比下这个Makefile和前面的Makefile有什么不同了。显然不是少了 build all。为什么不把test,放在第一个。
4、哦,对了,最后说一下,最后的正确执行结果就是 啥结果都没有 。不用吐,现在吐光了,后面还有更值得你要吐血的。
好,真收工了。
转自:http://my.oschina.net/luckystar/blog/67081