C-Namespace

记录两种C语言实现命令空间的方法

结构体封装

简单来说就是将某个独立的库对外封装一个统一的接口结构体structX,外部调用时都使用structX.aaa()来调用库中的方法。例如有一个foo的库,要对外提供test()方法,可在foo.h文件中定义一个命名空间结构体namespace_foo,结构体中定义好需要对外提供的方法成员,并在最后通过extern关键字对外暴露结构体变量Foo

1
2
3
4
5
6
7
/* foo.h */
typedef struct _namespace_foo {
const char *name;
const char *version;
int (*test)();
} namespace_foo;
extern namespace_foo const Foo;

结构体变量Foo的定义在foo.c文件中

1
2
3
4
5
6
7
8
9
10
11
/* foo.c */
static int foo_test()
{
/**/
}

namespace_foo const Foo = {
.name = 'Foo',
.version = '1.0',
.test = foo_test
}

外部要调用foo库中的函数,只需要引用foo.h头文件后,通过形如Foo.test()的方式就可以

1
2
3
4
5
6
7
8
9
10
11
/* main.c */

#include "foo.h"


int main(int argc, char **argv)
{
Foo.test();

return 0;
}

如果有另外一个库goo需要同时使用,只需要定义结构体变量Goo时的变量名称与Foo不同即可

利用ifdef

另一种方式是利用条件宏定义宏来重定义函数名称

1
2
3
4
5
6
7
/* foo.c */


int foo_test()
{
/**/
}
1
2
3
4
5
6
7
8
/* foo.h */


int foo_test();

#ifdef NAMESPACE_FOO
#define test(...) foo_test(__VA_ARGS__)
#endif

在外部使用foo库的函数前,需要通过宏声明NAMESPACE_FOO,然后再引用foo.h头文件,后续调用test()函数就等于调用foo_test()

1
2
3
4
5
6
7
8
9
/* main.c */

#define NAMESPACE_FOO
#include "foo.h"

int main(int argc, char **argv)
{
test();
}