C++ C语言中的名称空间
有没有办法(ab)使用C预处理器来模拟C中的名称空间 我的想法是这样的:C++ C语言中的名称空间,c++,c,namespaces,c-preprocessor,C++,C,Namespaces,C Preprocessor,有没有办法(ab)使用C预处理器来模拟C中的名称空间 我的想法是这样的: #define NAMESPACE name_of_ns some_function() { some_other_function(); } 这将转化为: name_of_ns_some_function() { name_of_ns_some_other_function(); } 您可以使用##运算符: #define FUN_NAME(namespace,name) namespace ## n
#define NAMESPACE name_of_ns
some_function() {
some_other_function();
}
这将转化为:
name_of_ns_some_function() {
name_of_ns_some_other_function();
}
您可以使用##运算符:
#define FUN_NAME(namespace,name) namespace ## name
并声明函数为:
void FUN_NAME(MyNamespace,HelloWorld)()
另一种选择是声明一个结构来保存所有函数,然后静态地定义函数。然后,您只需担心全局名称结构的名称冲突
// 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_bar
和my_baz
的多个定义并不冲突,因为它们是静态定义的,但底层函数仍然可以通过适当的命名空间结构访问。使用命名空间前缀时,我通常会为缩短的名称添加宏,在包含标题之前,可以通过#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(在评论中)描述的名称空间宏更干净、更有用的解决方案。我提出了以下方案: (标题) (实施)
与公认答案类似的方法如下:
// 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;
};
在使用函数时
foobar.some_func(10);
foobar.other_func();
下面是一个基于上述方法的示例,它将函数和结构的方法结合起来,创建伪名称空间NAMESPACE1和NAMESPACE2。与拥有一个包含函数的结构相比,这种方法的好处在于,包含函数的结构方法需要跨多个伪名称空间的标准化结构,而这并不总是可能的(或者根本不可能,或者如果没有大量的工作,可能无法改进代码),或者是可取的 不确定宏扩展顺序是否会成为一个问题,但这在GCC上起作用,似乎可以最大限度地减少所需的代码更改量,同时保持良好的可读性(尽管远不理想)
应用程序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);
}
header2.h和api2.c中的其他代码与header1.h和header2.h相同,为名称空间“NAMESPACE2”进行了修改。我使用基于结构的方法,有两个改进:我添加子结构来创建分层名称空间,当我想简化名称空间的路径时,我定义了一些简单的宏 让我们以Foobar库为例 foobar.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__
#ifndef __FOOBAR_TEXT_H__
#define __FOOBAR_TEXT_H__
void foobar_text__print(char *s);
#endif // __FOOBAR_TEXT_H__
foobar.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 <stdio.h>
#include "foobar_text.h"
void foobar_text__print(char *s) {
printf("%s\n", s);
}
然后,可以使用名称空间:
#include "foobar.h"
void main() {
foobar.text.print("it works");
}
但是foobar\u text\u print()
和foobar.text.print()
之间没有太大区别。我认为第二个更具可读性,但值得怀疑。因此,通过定义一些宏来简化这些名称空间变得非常有用:
#include "foobar.h"
#define txt foobar.text
#define date foobar.date
void main() {
char *today = date.getDateString();
txt.print(today);
}
这种分层名称空间定义速度快,易于理解,并且减少了代码的冗长
为了好玩,以下是
foobar.text的文件:
foobar\u text.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__
#ifndef __FOOBAR_TEXT_H__
#define __FOOBAR_TEXT_H__
void foobar_text__print(char *s);
#endif // __FOOBAR_TEXT_H__
foobar\u text.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 <stdio.h>
#include "foobar_text.h"
void foobar_text__print(char *s) {
printf("%s\n", s);
}
#包括
#包括“foobar_text.h”
void foobar_text____打印(字符*s){
printf(“%s\n”,s);
}
我写了一篇教程,介绍了如何使用C获得名称空间和/或模板的优势
对于基本名称空间,可以简单地将名称空间名称作为约定前缀
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
可以写成
struct MY_OBJECT_HANDLE;
struct MY_OBJECT_HANDLE *my_object_init();
void my_object_destroy( MY_OBJECT_HANDLE * & h );
void my_object_do_something(MY_OBJECT_HANDLE *h, ... );
使用名称空间和模板概念的第二种方法是使用宏连接和include。例如,我可以创建一个
template<T> T multiply<T>( T x, T y ) { return x*y }
乘法模板
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
我们现在可以定义int_乘法如下。在本例中,我将创建一个int_multiply.h/.c文件
整数乘
#ifndef _INT_MULTIPLY_H
#define _INT_MULTIPLY_H
#ifdef _multiply_
#undef _multiply_
#endif
#define _multiply_(NAME) int ## _ ## NAME
#ifdef _multiply_type_
#undef _multiply_type_
#endif
#define _multiply_type_ int
#include "multiply-template.h"
#endif
int_multiply.c
#include "int_multiply.h"
#include "multiply-template.c"
在所有这一切结束时,您将有一个函数和头文件
int int_multiply( int x, int y ) { return x * y }
我就提供的链接创建了一个更详细的教程。希望这对某人有帮助 我意识到这是一个老问题(11岁了),但我试图基本上实现我认为您最初想要的,正如您上面列出的那样
我希望在我的函数前面有一个名称空间。但是我想要改变名称空间的功能。默认情况下,我希望本例没有名称空间,但如果发生命名冲突,那么我希望能够为库中的所有函数预先设置名称空间。(与C++相比,在默认情况下,这里有一个命名空间稍微落后,并且使用<代码>使用名称空间,无论是< /Cord>),每次都需要指定命名空间。但是,就像C++一样,如果使用命名空间< /COS>语句和别名代码,请在<代码>中删除,则需要更新调用代码。您也可以编写一些其他宏序列来自动重命名调用,但这超出了我认为您要查找的范围
#include <stdio.h>
#define NAMESPACE(...) test_ //Use this as my prepender
//Where all the magic happens which could be included in a header file.
#ifndef NAMESPACE
//No Namespace by default
#define NAMESPACE(...)
#endif
//Actual replacements
#define NSPREPENDER(...) NSPROCESSING(NAMESPACE(), __VA_ARGS__)
#define NSPROCESSING(...) NSFINALIZE(__VA_ARGS__)
#define NSFINALIZE(a,b) a ## b
//BEGIN ACTUAL PROGRAM
//Prototype
void NSPREPENDER(myprint)();
int main()
{
test_myprint(); //If NAMESPACE(...) is defined to anything else, this code must change.
return 0;
}
//Implementation
void NSPREPENDER(myprint)()
{
puts("Testing");
}
#包括
#定义名称空间(…)测试//将其用作我的前置程序
//在这里,所有可以包含在头文件中的魔法都发生了。
#ifndef名称空间
//默认情况下没有命名空间
#定义命名空间(…)
#恩迪夫
//实际替换
#定义NSPREPENDER(…)NSPROCESSING(命名空间(),_VA_ARGS__;)
#定义NSPROCESSING(…)NSFINALIZE(_VA_ARGS__)
#定义(a,b)a##b
//开始实际程序
//原型
无效的打印机(myprint)();
int main()
{
test_myprint();//如果名称空间(…)定义为其他任何内容,则此代码必须更改。
返回0;
}
//实施
无效NSPREPENDER(myprint)()
{
看跌期权(“测试”);
}
此代码将仅在C99及以上版本上编译,因为它使用可变宏。这些宏执行一种递归形式,这样我们就可以从顶部定义的宏中获取值
所有it工程的明细:
- 我们定义了我们想要的名称空间
- 如果未定义任何内容,则设置默认值
- 做一系列的调用来绕过和(ab)使用prep
int int_multiply( int x, int y ) { return x * y }
#include <stdio.h>
#define NAMESPACE(...) test_ //Use this as my prepender
//Where all the magic happens which could be included in a header file.
#ifndef NAMESPACE
//No Namespace by default
#define NAMESPACE(...)
#endif
//Actual replacements
#define NSPREPENDER(...) NSPROCESSING(NAMESPACE(), __VA_ARGS__)
#define NSPROCESSING(...) NSFINALIZE(__VA_ARGS__)
#define NSFINALIZE(a,b) a ## b
//BEGIN ACTUAL PROGRAM
//Prototype
void NSPREPENDER(myprint)();
int main()
{
test_myprint(); //If NAMESPACE(...) is defined to anything else, this code must change.
return 0;
}
//Implementation
void NSPREPENDER(myprint)()
{
puts("Testing");
}
#include <stdio.h>
#define ns(x) gargantua_ ## x
struct ns(stats) {
int size;
};
int ns(get_size)(struct ns(stats) *st) {
return st->size;
}
void ns(set_size)(struct ns(stats) *st, int sz) {
st->size = sz;
}
int main(void) {
struct ns(stats) stats = {0};
ns(set_size)(&stats, 3);
printf("size=%d\n", ns(get_size)(&stats));
return 0;
}
struct gargantua_stats {
int size;
};
int gargantua_get_size(struct gargantua_stats *st) {
return st->size;
}
void gargantua_set_size(struct gargantua_stats *st, int sz) {
st->size = sz;
}
int main(void) {
struct gargantua_stats stats = {0};
gargantua_set_size(&stats, 3);
printf("size=%d\n", gargantua_get_size(&stats));
return 0;
}