C中的命名空间

有没有办法(AB)使用C预处理器来模拟C中的命名空间?

我正在考虑这方面的一些事情:

#define NAMESPACE name_of_ns some_function() { some_other_function(); } 

这将转化为:

 name_of_ns_some_function() { name_of_ns_some_other_function(); } 

当使用名称空间前缀时,我通常为缩写名称添加macros,可以在包含头之前通过#define NAMESPACE_SHORT_NAMES激活缩写名称。 头文件foobar.h可能看起来像这样:

 // inclusion guard #ifndef FOOBAR_H_ #define FOOBAR_H_ // long names void foobar_some_func(int); void foobar_other_func(); // short names #ifdef FOOBAR_SHORT_NAMES #define some_func(...) foobar_some_func(__VA_ARGS__) #define other_func(...) foobar_other_func(__VA_ARGS__) #endif #endif 

如果我想在包含文件中使用短名称,我会这样做

 #define FOOBAR_SHORT_NAMES #include "foobar.h" 

我发现这比使用Vinko Vrsalovic(在注释中)描述的名称空间macros更清洁和更有用。

另一种select是声明一个结构来保存所有的函数,然后静态地定义你的函数。 那么你只需要担心全局名称struct的名称冲突。

 // foo.h #ifndef FOO_H #define FOO_H typedef struct { int (* const bar)(int, char *); void (* const baz)(void); } namespace_struct; extern namespace_struct const foo; #endif // FOO_H // foo.c #include "foo.h" static int my_bar(int a, char * s) { /* ... */ } static void my_baz(void) { /* ... */ } namespace_struct const foo = { my_bar, my_baz } // main.c #include <stdio.h> #include "foo.h" int main(void) { foo.baz(); printf("%d", foo.bar(3, "hello")); return 0; } 

在上面的例子中, my_barmy_baz不能直接从main.c调用,只能通过foo调用。

如果您有一大堆声明具有相同签名的函数的名称空间,则可以标准化该集合的名称空间结构,并select在运行时使用哪个名称空间。

 // goo.h #ifndef GOO_H #define GOO_H #include "foo.h" extern namespace_struct const goo; #endif // GOO_H // goo.c #include "goo.h" static int my_bar(int a, char * s) { /* ... */ } static void my_baz(void) { /* ... */ } namespace_struct const goo = { my_bar, my_baz }; // other_main.c #include <stdio.h> #include "foo.h" #include "goo.h" int main(int argc, char** argv) { namespace_struct const * const xoo = (argc > 1 ? foo : goo); xoo->baz(); printf("%d", xoo->bar(3, "hello")); return 0; } 

my_barmy_baz的多重定义不会发生冲突,因为它们是静态定义的,但底层函数仍然可以通过适当的命名空间结构来访问。

你可以使用##运算符:

 #define FUN_NAME(namespace,name) namespace ## name 

并将函数声明为:

 void FUN_NAME(MyNamespace,HelloWorld)() 

看起来很尴尬。

我提出了以下计划:

(标题)

 // NS_PREFIX controls the prefix of each type and function declared in this // header, in order to avoid name collision. #define NS_PREFIX myprefix_ // Makes a string from argument (argument is not macro-expanded). #define stringify(arg) #arg // Concatenation that macro-expands its arguments. #define concat(p1, p2) _concat(p1, p2) // Macro expands the arguments. #define _concat(p1, p2) p1 ## p2 // Do the actual concatenation. // Append the namespace prefix to the identifier. #define ns(iden) concat(NS_PREFIX, iden) // header content, for instance : void ns(my_function)(int arg1, ns(t) arg2, int arg3); // Allow implementation files to use namespacing features, else // hide them from the including files. #ifndef _IMPL #undef NS_PREFIX #undef ns #undef stringify #undef concat #undef _concat #endif // _IMPL 

(实现)

 #define _IMPL #include "header.h" #undef __IMPL 

类似于接受的答案的方法如下:

 // inclusion guard #ifndef FOOBAR_H_ #define FOOBAR_H_ // long names void foobar_some_func(int); void foobar_other_func(); // qualified names #ifdef FOOBAR_SHORT_NAMES extern struct _foobar { void (*some_func)(int); void (*other_func)(); } foobar; #endif #endif 

这个头文件应该带有一个.c文件:

 #include "foobar.h" struct _foobar foobar = { foobar_some_func; foobar_other_func; }; 

当使用这些function时,

 foobar.some_func(10); foobar.other_func(); 

我使用基于结构的方法,有两个改进:我添加子结构来创build分层名称空间,当我想简化名称空间的path时,我定义了一些简单的macros。

Foobar图书馆为例。

foob​​ar.h中

 #ifndef __FOOBAR_H__ #define __FOOBAR_H__ // definition of the namespace's hierarchical structure struct _foobar_namespace { struct { void (*print)(char *s); } text; struct { char *(*getDateString)(void); } date; }; // see the foobar.c file // it must be the only one defining the FOOBAR macro # ifndef FOOBAR // definition of the namespace global variable extern struct _foobar_namespace foobar; # endif // FOOBAR #endif // __FOOBAR_H__ 

foob​​ar.c但是

 // the FOOBAR macro is needed to avoid the // extern foobar variable declaration #define FOOBAR #include "foobar.h" #include "foobar_text.h" #include "foobar_date.h" // creation of the namespace global variable struct _foobar_namespace foobar = { .text = { .print = foobar_text__print }, .date = { .getDateString = foobar_date__getDateString } }; 

然后,可以使用命名空间:

 #include "foobar.h" void main() { foobar.text.print("it works"); } 

foobar_text__print()foobar.text.print()之间没有太大的区别。 我认为第二个更具可读性,但是值得怀疑。 所以通过定义一些macros来简化这些命名空间变得非常有用:

 #include "foobar.h" #define txt foobar.text #define date foobar.date void main() { char *today = date.getDateString(); txt.print(today); } 

这种层次化的命名空间是快速定义的,易于理解的,并减less代码冗长。


只是为了好玩,这里是foobar.text代码的文件:

foob​​ar_text.h

 #ifndef __FOOBAR_TEXT_H__ #define __FOOBAR_TEXT_H__ void foobar_text__print(char *s); #endif // __FOOBAR_TEXT_H__ 

foob​​ar_text.c

 #include <stdio.h> #include "foobar_text.h" void foobar_text__print(char *s) { printf("%s\n", s); } 

这里是一个构build上面的方法的例子,并且将funcs和structure结合起来创build伪命名空间NAMESPACE1和NAMESPACE2。 这样做的好处在于拥有一个保存函数的结构,这个结构保持函数方法需要跨越多个伪名称空间的标准化结构,这并不总是可能的(根本不可能,或者没有很多可以certificate的工作没有改善代码)或可取的。

不确定macros扩展顺序是否可能是一个问题,但是这对GCC起作用,并似乎尽量减less所需的代码更改量,同时保持可观的(尽pipe很不理想)可读性。


application.c:

 #include <stdio.h> #include "header1.h" #include "header2.h" /* use NAMESPACE1 and NAMESPACE2 macros to choose namespace */ int main() { NAMESPACE1(mystruct) data1; // structure specific to this namespace NAMESPACE2(mystruct) data2; data1.n1 = '1'; data1.c = 'a'; data2.n2 = '2'; data2.c = 'a'; NAMESPACE1(print_struct)(&data1); // function specific to this namespace NAMESPACE2(print_struct)(&data2); } 

那么header1.h

 /* the below block is unnecessary, but gets rid of some compiler warnings */ #ifdef NAMESPACE_REAL #undef NAMESPACE_REAL #endif /* edit the below lines to change the three occurrences of NAMESPACE1 to the desired namespace */ #define NAMESPACE1(name) NAMESPACE1 ## _ ## name #define NAMESPACE_REAL(name) NAMESPACE1(name) /* don't edit the next block */ #define TYPEDEF(name, ...) typedef struct NAMESPACE_REAL(name) { __VA_ARGS__ } NAMESPACE_REAL(name) #define STRUCT(name) struct NAMESPACE_REAL(name) #define FUNC(name) NAMESPACE_REAL(name) /* normal header code, using FUNC and STRUCT macros */ #include <stdio.h> TYPEDEF(mystruct, char n1; char c; ); void FUNC(print_struct)(STRUCT(mystruct) *data); /* don't edit the rest */ #undef TYPEDEF 

api1.c:

 #include "header1.h" /* normal code, using FUNC and STRUCT macros */ void FUNC(print_struct)(STRUCT(mystruct) *data) { printf("this is the struct from namespace1: %c %c\n", data->n1, data->c); } /* don't edit the rest */ #undef STRUCT #undef FUNC #undef NAMESPACE #undef NAMESPACE_REAL 

header2.h和api2.c中的其他代码与header1.h和header2.h相同,对名称空间“NAMESPACE2”进行了修改