Namespaces
Variants

Lookup and name spaces

From cppreference.net

Wenn ein Identifier in einem C-Programm angetroffen wird, wird eine Suche durchgeführt, um die Deklaration zu lokalisieren, die diesen Identifier eingeführt hat und die gegenwärtig im Gültigkeitsbereich ist. C erlaubt, dass mehr als eine Deklaration für denselben Identifier gleichzeitig im Gültigkeitsbereich sein kann, wenn diese Identifier zu verschiedenen Kategorien gehören, genannt Namensräume :

1) Namensraum für Labels: alle als Labels deklarierten Bezeichner.
2) Tagnamen: alle Bezeichner, die als Namen von structs , unions und enumerated types deklariert sind. Beachten Sie, dass alle drei Arten von Tags einen gemeinsamen Namensraum teilen.
3) Mitgliedernamen: alle Bezeichner, die als Mitglieder einer beliebigen struct oder union deklariert sind. Jede struct und union führt ihren eigenen Namensraum dieser Art ein.
4) Globaler Attribut-Namensraum: Attribut-Tokens definiert durch den Standard oder implementierungsdefinierte Attribut-Präfixe.
5) Nicht-standardisierte Attributnamen: Attributnamen, die Attribut-Präfixen folgen. Jedes Attribut-Präfix hat einen separaten Namensraum für die implementierungsdefinierten Attribute, die es einführt.
(seit C23)
6) Alle anderen Bezeichner, genannt gewöhnliche Bezeichner zur Unterscheidung von (1-5) (Funktionsnamen, Objektnamen, Typdef-Namen, Aufzählungskonstanten).

Zum Zeitpunkt der Namenssuche wird der Namensraum eines Identifikators durch die Art seiner Verwendung bestimmt:

1) Ein Bezeichner, der als Operand einer goto-Anweisung erscheint, wird im Label-Namensraum nachgeschlagen.
2) Der Bezeichner, der dem Schlüsselwort struct , union oder enum folgt, wird im Tag-Namensraum nachgeschlagen.
3) Der Bezeichner, der dem Member-Zugriffsoperator oder dem Member-Zugriffsoperator über Zeiger folgt, wird im Namensraum der Member des Typs gesucht, der durch den linken Operanden des Member-Zugriffsoperators bestimmt wird.
4) Ein Bezeichner, der direkt in einer Attributspezifikation erscheint ( [ [ ... ] ] ) wird im globalen Attributnamensraum gesucht.
5) Ein Bezeichner, der auf den :: Token folgt, der einem Attributpräfix folgt, wird im Namensraum gesucht, der durch das Attributpräfix eingeführt wird.
(seit C23)
6) alle anderen Bezeichner werden im Namensraum der gewöhnlichen Bezeichner gesucht.

Inhaltsverzeichnis

Hinweise

Die Namen von Makros gehören zu keinem Namensraum, da sie vom Präprozessor vor der semantischen Analyse ersetzt werden.

Es ist gängige Praxis, die Namen von Structs/Unions/Enums mittels einer typedef -Deklaration in den Namensraum der gewöhnlichen Bezeichner einzufügen:

struct A { };       // führt den Namen A im Tag-Namensraum ein
typedef struct A A; // zuerst wird A nach "struct" gesucht und findet einen im Tag-Namensraum
                    // führt dann den Namen A im gewöhnlichen Namensraum ein
struct A* p;        // OK, dieses A wird im Tag-Namensraum gesucht
A* q;               // OK, dieses A wird im gewöhnlichen Namensraum gesucht

Ein bekanntes Beispiel für die Verwendung desselben Bezeichners in zwei Namensräumen ist der Bezeichner stat aus dem POSIX-Header sys/stat.h . Er benennt eine Funktion , wenn er als gewöhnlicher Bezeichner verwendet wird, und kennzeichnet eine Struktur , wenn er als Tag verwendet wird.

Im Gegensatz zu C++ sind Aufzählungskonstanten keine struct-Mitglieder, und ihr Namensraum ist der Namensraum gewöhnlicher Bezeichner, und da es in C keinen struct-Gültigkeitsbereich gibt, ist ihr Gültigkeitsbereich der Gültigkeitsbereich, in dem die struct-Deklaration erscheint:

struct tagged_union {
   enum {INT, FLOAT, STRING} type;
   union {
      int integer;
      float floating_point;
      char *string;
   };
} tu;
tu.type = INT; // OK in C, Fehler in C++

Wenn ein Standardattribut, ein Attributpräfix oder ein nicht-standardisiertes Attribut nicht unterstützt wird, wird das ungültige Attribut selbst ignoriert, ohne einen Fehler zu verursachen.

(since C23)

Beispiel

void foo (void) { return; } // gewöhnlicher Namensraum, Dateigültigkeitsbereich
struct foo {      // Tag-Namensraum, Dateigültigkeitsbereich
    int foo;      // Mitgliedsnamensraum für diese struct foo, Dateigültigkeitsbereich
    enum bar {    // Tag-Namensraum, Dateigültigkeitsbereich
        RED       // gewöhnlicher Namensraum, Dateigültigkeitsbereich
    } bar;        // Mitgliedsnamensraum für diese struct foo, Dateigültigkeitsbereich
    struct foo* p; // OK: verwendet Tag/Dateigültigkeitsbereich-Name "foo"
};
enum bar x; // OK: verwendet Tag/Dateigültigkeitsbereich bar
// int foo; // Fehler: gewöhnlicher Namensraum foo bereits im Gültigkeitsbereich
//union foo { int a, b; }; // Fehler: Tag-Namensraum foo im Gültigkeitsbereich
int main(void)
{
    goto foo; // OK verwendet "foo" aus Label-Namensraum/Funktionsgültigkeitsbereich
    struct foo { // Tag-Namensraum, Blockgültigkeitsbereich (verdeckt Dateigültigkeitsbereich)
       enum bar x; // OK, verwendet "bar" aus Tag-Namensraum/Dateigültigkeitsbereich
    };
    typedef struct foo foo; // OK: verwendet foo aus Tag-Namensraum/Blockgültigkeitsbereich
                            // definiert gewöhnlichen Blockgültigkeitsbereich-foo (verdeckt Dateigültigkeitsbereich)
    (foo){.x=RED}; // verwendet gewöhnlichen/Blockgültigkeitsbereich-foo und gewöhnlichen/Dateigültigkeitsbereich-RED
foo:; // Label-Namensraum, Funktionsgültigkeitsbereich
}

Referenzen

  • C17-Standard (ISO/IEC 9899:2018):
  • 6.2.3 Namensräume von Bezeichnern (S: 29-30)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.2.3 Namensräume von Bezeichnern (S: 37)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.2.3 Namensräume von Bezeichnern (S: 31)
  • C89/C90 Standard (ISO/IEC 9899:1990):
  • 3.1.2.3 Namensräume von Bezeichnern

Siehe auch

C++-Dokumentation für Name lookup