载前的说明
forward declaration可以达到向用户隐蔽信息的目的,linux内核源码,关于forward declaration的使用无处不在,这也体现了linux内核高内聚低耦合的设计思想。jserv老师在这方面做了很详细的解说,非常值得深入学习和研究。
由于头条无法添加外部链接,因此我会在标有下划线文字部分添加相应的链接地址以及说明。
forward declaration 搭配指针的技巧
案例: oltk是Openmoko为了测试而开发出的精简绘图系统,支持触摸屏操作,源码不到1000行C语言程序。执行画面: (oltk的开发者是olv )
- oltk.h
<code>struct oltk; // 声明 (incomplete type, void) struct oltk_button; typedef void oltk_button_cb_click(struct oltk_button *button, void *data); typedef void oltk_button_cb_draw(struct oltk_button *button, struct oltk_rectangle *rect, void *data); struct oltk_button *oltk_button_add(struct oltk *oltk, int x, int y, int width, int height);/<code>
struct oltk和struct oltk_button没有具体的定义(definition)或实现(implementation),仅有声明(declaration)。
- oltk.c
<code>struct oltk { struct gr *gr; struct oltk_button **zbuttons; ... struct oltk_rectangle invalid_rect; };/<code>
软件接口(interface)位于oltk.h,不管struct oltk内容怎么修改,已公开的函数如oltk_button_add都是透过pointer存取给定的地址,而不用顾虑具体struct oltk的实现,如此一来,不仅可以隐藏实现细节,还能有非常良好的兼容性(binary compatibility)。
同理,struct oltk_button 不管怎么变更,在struct oltk 里面也是用给定的pointer 去存取,保留未来实现的弹性。
<code>想更深入了解oltk的实现,具体参考 oltk的gihub地址:https://github.com/openmoko/system-test-suite/tree/master/gta02-dm2/src/oltk/<code>
简单的例子参考
说明
- a.h,开放给客户的接口头文件
- internal.h, 定义了一些结构体,且会被多个.c调用
- a.c,提供了a.h中的一部分接口,且会创建主要的handle
- b.c,提供了a.h中的另一部分接口
相关文件
a.h
这里只声明了test_lib_t 就是struct test_lib_st 类型 但没有给test_lib_st的定义,它的定义可以放到其它的内部c/h文件中, 从而达到向用户隐藏的目的。
即,用户可以使用test_lib_t,但看不到它的内部成员定义。
<code>#ifndef INCLUDE_A_H_ #define INCLUDE_A_H_ typedef struct test_lib_st test_lib_t; // 创建并返回test_lib的handle test_lib_t* test_lib_create(void); void test_lib_destroy(test_lib_t* test_lib); ... int test_print(test_lib_t* test_lib); ... #endif // INCLUDE_A_H_ /<code>
internal.h
<code>#ifndef INCLUDE_INTERNAL_H_ #define INCLUDE_INTERNAL_H_ // 这里声明内部需要用到的所有成员变量 struct test_lib_st { int i; char* p; ... }; #endif // INCLUDE_INTERNAL_H_ /<code>
a.c
<code>#include "a.h" #include "internal.h" test_lib_t* test_lib_create(void) { test_lib_t* m = malloc(sizeof(test_lib_t)); memset(m, 0, sizeof(test_lib_t)); // 初始化各成员变量 ... return m; Error: return NULL; } void test_lib_destroy(test_lib_t* test_lib) { free(test_lib); return; }/<code>
b.c
<code>#include "a.h" #include "internal.h" /*因为这里也include了internal.h, 所以此C文件中也可以使用 test_lib_t */ int test_print(test_lib_t* test_lib) { ... }/<code>