Namespaces zu haben, scheint für die meisten Sprachen ein Kinderspiel zu sein. Aber soweit ich das beurteilen kann, unterstützt ANSI C dies nicht. Warum nicht? Gibt es Pläne, es in einen zukünftigen Standard aufzunehmen?
Namespaces zu haben, scheint für die meisten Sprachen ein Kinderspiel zu sein. Aber soweit ich das beurteilen kann, unterstützt ANSI C dies nicht. Warum nicht? Gibt es Pläne, es in einen zukünftigen Standard aufzunehmen?
Antworten:
C hat Namespaces. Eine für Struktur-Tags und eine für andere Typen. Betrachten Sie die folgende Definition:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Der erste hat das Tag foo und der spätere wird mit einem typedef zum Typ foo gemacht. Es kommt immer noch nicht zu Namenskonflikten. Dies liegt daran, dass Struktur-Tags und -Typen (integrierte Typen und typdefinierte Typen) in separaten Namespaces gespeichert sind.
Was C nicht erlaubt, ist, durch Willen einen neuen Namespace zu erstellen . C wurde standardisiert, bevor dies in einer Sprache als wichtig erachtet wurde, und das Hinzufügen von Namespaces würde auch die Abwärtskompatibilität gefährden, da die Namensveränderung erforderlich ist, um richtig zu funktionieren. Ich denke, dies kann auf technische Aspekte zurückgeführt werden, nicht auf die Philosophie.
EDIT: JeremyP hat mich glücklicherweise korrigiert und die Namespaces erwähnt, die ich verpasst habe. Es gibt Namespaces für Labels und auch für Struktur- / Gewerkschaftsmitglieder.
struct
Definition deklariert einen neuen Namespace für ihre Mitglieder. Ich befürworte weder die Ausnutzung dieser Tatsache, noch sind mir Mittel zur Ausnutzung dieser Tatsache bekannt, da struct
s keine statischen Mitglieder haben kann.
Der Vollständigkeit halber gibt es in C verschiedene Möglichkeiten, die "Vorteile" von Namespaces zu erzielen.
Eine meiner Lieblingsmethoden ist die Verwendung einer Struktur, um eine Reihe von Methodenzeigern zu speichern, die die Schnittstelle zu Ihrer Bibliothek / etc bilden.
Anschließend verwenden Sie eine externe Instanz dieser Struktur, die Sie in Ihrer Bibliothek initialisieren und auf alle Ihre Funktionen verweisen. Auf diese Weise können Sie Ihre Namen in Ihrer Bibliothek einfach halten, ohne auf den Client-Namespace zuzugreifen (außer der externen Variablen im globalen Bereich, 1 Variable gegenüber möglicherweise Hunderten von Methoden.)
Es sind einige zusätzliche Wartungsarbeiten erforderlich, aber ich bin der Meinung, dass diese minimal sind.
Hier ist ein Beispiel:
/* 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 */
Die Verwendung von . Die Syntax stellt eine starke Assoziation zur klassischen Library_function () Library_some_value-Methode her. Es gibt jedoch einige Einschränkungen, zum einen können Sie keine Makros als Funktionen verwenden.
library.method1()
?
.c
Dateien standardmäßig statisch zu machen. Daher sind die einzigen Funktionen, die verfügbar gemacht werden, diejenigen, die explizit in der const struct
Definition in der .c
Datei verfügbar gemacht werden.
function1
/ method2
beim Kompilieren mit -O2
und -flto
. Wenn Sie solche Bibliotheken nicht zusammen mit Ihrer eigenen Quelle kompilieren, erhöht dieser Ansatz die Funktionsaufrufe um einen gewissen Aufwand.
C hat Namespaces. Die Syntax lautet namespace_name
. Sie können sie sogar wie in verschachteln general_specific_name
. Wenn Sie auf Namen zugreifen möchten, ohne jedes Mal den Namespace-Namen ausschreiben zu müssen, fügen Sie die entsprechenden Präprozessor-Makros in eine Header-Datei ein, z
#define myfunction mylib_myfunction
Dies ist viel sauberer als das Mangeln von Namen und die anderen Gräueltaten, die bestimmte Sprachen begehen, um Namespaces bereitzustellen.
In der Vergangenheit haben C-Compiler keine Namen entstellt (unter Windows, aber das Verfälschen für die cdecl
aufrufende Konvention besteht darin, nur ein Unterstrichpräfix hinzuzufügen).
Dies erleichtert die Verwendung von C-Bibliotheken aus anderen Sprachen (einschließlich Assembler) und ist einer der Gründe, warum häufig extern "C"
Wrapper für C ++ - APIs angezeigt werden.
nur historische Gründe. Niemand dachte damals daran, so etwas wie einen Namespace zu haben. Außerdem versuchten sie wirklich, die Sprache einfach zu halten. Sie können es in der Zukunft haben
Keine Antwort, aber kein Kommentar. C bietet keine Möglichkeit, namespace
explizit zu definieren . Es hat einen variablen Umfang. Beispielsweise:
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);
}
Sie können qualifizierte Namen für Variablen und Funktionen verwenden:
mylib.h
void mylib_init();
void mylib_sayhello();
Der einzige Unterschied zu Namespaces besteht darin, dass Sie using
nicht importiert werden können from mylib
.
namespace mylib { void init(); void say_hello(); }
ebenfalls wichtig sind (ish).
ANSI C wurde erfunden, bevor es Namespaces gab.
Weil Leute, die diese Funktion zu C hinzufügen möchten, sich nicht zusammengetan und organisiert haben, um Druck auf Compiler-Autorenteams und ISO-Gremien auszuüben.
C unterstützt keine Namespaces wie C ++. Die Implementierung von C ++ - Namespaces entstellt die Namen. Mit dem unten beschriebenen Ansatz können Sie die Vorteile von Namespaces in C ++ nutzen, während Sie Namen haben, die nicht entstellt sind. Mir ist klar, dass die Art der Frage ist, warum C keine Namespaces unterstützt (und eine triviale Antwort wäre, dass dies nicht der Fall ist, weil es nicht implementiert wurde :)). Ich dachte nur, dass es jemandem helfen könnte zu sehen, wie ich die Funktionalität von Vorlagen und Namespaces implementiert habe.
Ich habe ein Tutorial geschrieben, wie man mit C Namespaces und / oder Vorlagen nutzen kann.
Namespaces und Vorlagen in C (mithilfe verknüpfter Listen)
Für den Basis-Namespace kann man dem Namespace-Namen einfach eine Konvention voranstellen.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
kann geschrieben werden als
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, ... );
Ein zweiter Ansatz, den ich benötigt habe und der das Konzept von Namespace und Vorlagen verwendet, ist die Verwendung der Makroverkettung und des Einschlusses. Zum Beispiel kann ich eine erstellen
template<T> T multiply<T>( T x, T y ) { return x*y }
Verwenden von Vorlagendateien wie folgt
multiplizieren-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
multiplizieren-template.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
Wir können int_multiply nun wie folgt definieren. In diesem Beispiel erstelle ich eine int_multiply.h / .c-Datei.
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"
Am Ende all dessen haben Sie eine Funktions- und Header-Datei für.
int int_multiply( int x, int y ) { return x * y }
Ich habe ein viel detaillierteres Tutorial zu den bereitgestellten Links erstellt, das zeigt, wie es mit verknüpften Listen funktioniert. Hoffentlich hilft das jemandem!