你所不知道的C語言:指針篇(續)

载前的说明

forward declaration可以达到向用户隐蔽信息的目的,linux内核源码,关于forward declaration的使用无处不在,这也体现了linux内核高内聚低耦合的设计思想。jserv老师在这方面做了很详细的解说,非常值得深入学习和研究。

由于头条无法添加外部链接,因此我会在标有下划线文字部分添加相应的链接地址以及说明。

forward declaration 搭配指针的技巧

案例: oltk是Openmoko为了测试而开发出的精简绘图系统,支持触摸屏操作,源码不到1000行C语言程序。执行画面: (oltk的开发者是olv )

你所不知道的C语言:指针篇(续)

  • 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>


分享到:


相關文章: