61 votes

Espaces de noms en C

Existe-t-il un moyen (ab) d'utiliser le préprocesseur C pour émuler des espaces de noms en C?

Je pense à quelque chose dans ce sens:

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

Cela serait traduit en:

 name_of_ns_some_function() {
    name_of_ns_some_other_function();
}
 

90voto

rampion Points 38697

Une autre alternative serait de déclarer une structure pour contenir tous vos fonctions, puis définissez vos fonctions de façon statique. Ensuite vous n'avez plus à vous soucier des conflits de nom pour le nom global 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;
}

Dans l'exemple ci-dessus, my_bar et my_baz ne peut pas être appelée directement à partir des principaux.c, que par l' foo.

Si vous avez un tas d'espaces de noms que de déclarer des fonctions avec les mêmes signatures, alors vous pouvez normaliser votre espace de noms de la structure de l'ensemble, et de choisir un espace de noms à utiliser lors de l'exécution.

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

Les multiples définitions de l' my_bar et my_baz n'entrent pas en conflit, car ils sont définis de manière statique, mais que les fonctions sous-jacentes sont toujours accessibles par l'intermédiaire de l'espace de noms struct.

56voto

Christoph Points 64389

Lorsque j'utilise des préfixes d'espaces de noms, j'ajoute normalement des macros pour les noms abrégés pouvant être activées via #define NAMESPACE_SHORT_NAMES avant l'inclusion de l'en-tête. Un en-tête foobar.h pourrait ressembler à ceci:

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

Si je veux utiliser des noms abrégés dans un fichier inclus, je ferai

 #define FOOBAR_SHORT_NAMES
#include "foobar.h"
 

Je trouve cette solution plus propre et plus utile que d’utiliser des macros d’espace de noms comme décrit par Vinko Vrsalovic (dans les commentaires).

13voto

Mehrdad Afshari Points 204872

Vous pouvez utiliser l'opérateur ##:

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

et déclarer les fonctions en tant que:

 void FUN_NAME(MyNamespace,HelloWorld)()
 

Cela semble plutôt bizarre.

8voto

Norswap Points 1264

Je suis venu avec le schéma suivant:

(entête)

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

(la mise en oeuvre)

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

4voto

Earth Engine Points 1795

Une approche similaire à la réponse acceptée est la suivante:

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

ce fichier d'en-tête doit être accompagné d'un fichier .c:

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

en utilisant les fonctions,

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X