Avoir des espaces de noms semble une évidence pour la plupart des langues. Mais pour autant que je sache, ANSI C ne le prend pas en charge. Pourquoi pas? Avez-vous l'intention de l'inclure dans une future norme?
Avoir des espaces de noms semble une évidence pour la plupart des langues. Mais pour autant que je sache, ANSI C ne le prend pas en charge. Pourquoi pas? Avez-vous l'intention de l'inclure dans une future norme?
Réponses:
C a des espaces de noms. Un pour les balises de structure et un pour les autres types. Considérez la définition suivante:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Le premier a la balise foo, et le dernier est transformé en type foo avec un typedef. Il n'y a toujours pas de conflit de noms. Cela est dû au fait que les balises et les types de structure (types intégrés et types à défaut typé) vivent dans des espaces de noms séparés.
Ce que C ne permet pas, c'est de créer un nouvel espace de noms par volonté. C a été normalisé avant que cela ne soit considéré comme important dans une langue, et l'ajout d'espaces de noms menacerait également la compatibilité ascendante, car cela nécessite une modification des noms pour fonctionner correctement. Je pense que cela peut être attribué à des aspects techniques et non à la philosophie.
EDIT: JeremyP m'a heureusement corrigé et a mentionné les espaces de noms que j'avais manqués. Il existe des espaces de noms pour les étiquettes et pour les membres de struct / union.
struct
définition déclare un nouvel espace de noms pour ses membres. Je ne préconise pas d'exploiter ce fait, et je ne connais aucun moyen de l'exploiter car struct
s ne peut pas avoir de membres statiques.
Par souci d'exhaustivité, il existe plusieurs façons d'obtenir les "avantages" que vous pourriez obtenir des espaces de noms, en C.
Une de mes méthodes préférées consiste à utiliser une structure pour héberger un tas de pointeurs de méthode qui sont l'interface de votre bibliothèque / etc.
Vous utilisez ensuite une instance externe de cette structure que vous initialisez à l'intérieur de votre bibliothèque pointant vers toutes vos fonctions. Cela vous permet de garder vos noms simples dans votre bibliothèque sans marcher sur l'espace de noms des clients (autre que la variable externe à portée globale, 1 variable contre éventuellement des centaines de méthodes ..)
Il y a un peu d'entretien supplémentaire impliqué mais je pense que c'est minime.
Voici un exemple:
/* interface.h */
struct library {
const int some_value;
void (*method1)(void);
void (*method2)(int);
/* ... */
};
extern const struct library Library;
/* interface.h */
/* interface.c */
#include "interface.h"
void method1(void)
{
...
}
void method2(int arg)
{
...
}
const struct library Library = {
.method1 = method1,
.method2 = method2,
.some_value = 36
};
/* end interface.c */
/* client code */
#include "interface.h"
int main(void)
{
Library.method1();
Library.method2(5);
printf("%d\n", Library.some_value);
return 0;
}
/* end */
L'utilisation de . La syntaxe crée une forte association avec la méthode classique Library_function () Library_some_value. Il y a cependant quelques limitations, vous ne pouvez pas utiliser de macros comme fonctions.
library.method1()
?
.c
fichiers statiques par défaut, donc les seules fonctions exposées sont celles explicitement exposées dans la const struct
définition du .c
fichier.
function1
/ method2
lors de la compilation avec -O2
et -flto
. À moins que vous ne compiliez de telles bibliothèques avec votre propre source, cette approche ajoutera une surcharge à ses appels de fonction.
C a des espaces de noms. La syntaxe est namespace_name
. Vous pouvez même les imbriquer comme dans general_specific_name
. Et si vous voulez pouvoir accéder aux noms sans écrire le nom de l'espace de noms à chaque fois, incluez les macros de préprocesseur appropriées dans un fichier d'en-tête, par exemple
#define myfunction mylib_myfunction
C'est beaucoup plus propre que la manipulation des noms et les autres atrocités que certaines langues s'engagent à fournir des espaces de noms.
Historiquement, les compilateurs C ne modifient pas les noms (ils le font sous Windows, mais le cdecl
convention d'appel consiste uniquement à ajouter un préfixe de soulignement).
Cela facilite l'utilisation des bibliothèques C d'autres langages (y compris l'assembleur) et est l'une des raisons pour lesquelles vous voyez souvent des extern "C"
wrappers pour les API C ++.
juste des raisons historiques. personne n'a pensé à avoir quelque chose comme un espace de noms à ce moment-là. De plus, ils essayaient vraiment de garder le langage simple. Ils peuvent l'avoir dans le futur
Pas une réponse, mais pas un commentaire. C ne fournit pas un moyen de définir namespace
explicitement. Il a une portée variable. Par exemple:
int i=10;
struct ex {
int i;
}
void foo() {
int i=0;
}
void bar() {
int i=5;
foo();
printf("my i=%d\n", i);
}
void foobar() {
foo();
bar();
printf("my i=%d\n", i);
}
Vous pouvez utiliser des noms qualifiés pour les variables et les fonctions:
mylib.h
void mylib_init();
void mylib_sayhello();
La seule différence avec les espaces de noms est que vous ne pouvez pas être using
et ne pouvez pas importer from mylib
.
namespace mylib { void init(); void say_hello(); }
ce qui est également important (ish).
ANSI C a été inventé avant les espaces de noms.
Parce que les gens qui veulent ajouter cette capacité à C ne se sont pas réunis et ne se sont pas organisés pour faire pression sur les équipes de compilateurs et sur les organismes ISO.
C ne prend pas en charge les espaces de noms comme C ++. L'implémentation des espaces de noms C ++ modifie les noms. L'approche décrite ci-dessous vous permet de tirer parti des espaces de noms en C ++ tout en ayant des noms qui ne sont pas mutilés. Je me rends compte que la nature de la question est de savoir pourquoi C ne prend pas en charge les espaces de noms (et une réponse triviale serait que ce n'est pas le cas parce qu'il n'a pas été implémenté :)) J'ai juste pensé que cela pourrait aider quelqu'un à voir comment j'ai implémenté la fonctionnalité des modèles et des espaces de noms.
J'ai rédigé un tutoriel sur la façon de tirer parti des espaces de noms et / ou des modèles en utilisant C.
Espaces de noms et modèles en C
Espaces de noms et modèles en C (à l'aide de listes liées)
Pour l'espace de noms de base, on peut simplement préfixer le nom de l'espace de noms comme convention.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
peut être écrit comme
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, ... );
Une deuxième approche dont j'avais besoin et qui utilise le concept d'espacement de noms et de modèles consiste à utiliser la concaténation de macros et à inclure. Par exemple, je peux créer un
template<T> T multiply<T>( T x, T y ) { return x*y }
en utilisant des fichiers modèles comme suit
multiply-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
multiply-template.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
Nous pouvons maintenant définir int_multiply comme suit. Dans cet exemple, je vais créer un fichier int_multiply.h / .c.
int_multiply.h
#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"
À la fin de tout cela, vous aurez une fonction et un fichier d'en-tête pour.
int int_multiply( int x, int y ) { return x * y }
J'ai créé un tutoriel beaucoup plus détaillé sur les liens fournis qui montrent comment cela fonctionne avec les listes liées. Espérons que cela aide quelqu'un!