当前位置:  开发笔记 > 编程语言 > 正文

C中的命名空间

如何解决《C中的命名空间》经验,为你挑选了5个好方法。

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

我正在考虑以下几点:

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

这将被翻译为:

name_of_ns_some_function() {
    name_of_ns_some_other_function();
}

rampion.. 82

另一种方法是声明一个struct来保存你的所有函数,然后静态地定义你的函数.然后,您只需要担心全局名称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 
#include "foo.h"
int main(void) {
  foo.baz();
  printf("%d", foo.bar(3, "hello"));
  return 0;
}

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

如果您有一堆声明具有相同签名的函数的命名空间,那么您可以标准化该集合的命名空间结构,并选择在运行时使用哪个命名空间.

// 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 
#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_bar并且my_baz不冲突,因为它们是静态定义的,但是底层函数仍然可以通过适当的命名空间结构访问.



1> rampion..:

另一种方法是声明一个struct来保存你的所有函数,然后静态地定义你的函数.然后,您只需要担心全局名称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 
#include "foo.h"
int main(void) {
  foo.baz();
  printf("%d", foo.bar(3, "hello"));
  return 0;
}

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

如果您有一堆声明具有相同签名的函数的命名空间,那么您可以标准化该集合的命名空间结构,并选择在运行时使用哪个命名空间.

// 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 
#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_bar并且my_baz不冲突,因为它们是静态定义的,但是底层函数仍然可以通过适当的命名空间结构访问.


我甚至不称之为黑客 - 你正在使用语言功能组织暴露的功能.+1为干净的解决方案!
这是一个优雅的"黑客".+1

2> Christoph..:

使用名称空间前缀时,我通常会为缩短的名称添加宏,这些名称可以#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所描述的命名空间宏(在评论中)更清晰,更有用.



3> Mehrdad Afsh..:

你可以使用##运算符:

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

并将函数声明为:

void FUN_NAME(MyNamespace,HelloWorld)()

看起来很尴尬.



4> Norswap..:

我想出了以下方案:

(标题)

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



5> 小智..:

我使用基于结构的方法,并进行了两个改进:添加子结构以创建分层名称空间,并且当我想简化名称空间的路径时定义一些简单的宏。

让我们以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()。我认为第二个更具可读性,但是值得怀疑。因此,通过定义一些宏来简化这些名称空间将变得非常有用:

#include "foobar.h"

#define txt    foobar.text
#define date   foobar.date

void main() {
    char *today = date.getDateString();
    txt.print(today);
}

这种分层的名称空间可以快速定义,易于理解并减少代码的冗长性。


只是为了好玩,这里是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 
#include "foobar_text.h"

void foobar_text__print(char *s) {
    printf("%s\n", s);
}

推荐阅读
我我檬檬我我186
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有