Namensräume
Varianten
Aktionen

Nachschlagen und Namensräume

Von cppreference.com
< c‎ | Sprache

Wenn ein Bezeichner in einem C-Programm angetroffen wird, wird eine Suche durchgeführt, um die Deklaration zu finden, die diesen Bezeichner eingeführt hat und die aktuell im Geltungsbereich liegt. C erlaubt, dass mehr als eine Deklaration für denselben Bezeichner gleichzeitig im Geltungsbereich liegt, wenn diese Bezeichner zu verschiedenen Kategorien gehören, die als Namensräume bezeichnet werden.

1) Label-Namensraum: Alle als Labels deklarierten Bezeichner.
2) Tag-Namen: Alle als Namen von Strukturen, Unionen und Aufzählungstypen deklarierten Bezeichner. Beachten Sie, dass alle drei Arten von Tags denselben Namensraum teilen.
3) Member-Namen: Alle als Member einer beliebigen Struktur oder Union deklarierten Bezeichner. Jede Struktur und Union führt ihren eigenen Namensraum dieser Art ein.
4) Globaler Attribut-Namensraum: Attribut-Token, die vom Standard oder von implementierungsdefinierten Attribut-Präfixen definiert wurden.
5) Nicht-Standard-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, die als gewöhnliche Bezeichner bezeichnet werden, um sie von (1-5) zu unterscheiden (Funktionsnamen, Objektnamen, Typedef-Namen, Aufzählungskonstanten).

Zum Zeitpunkt der Suche wird der Namensraum eines Bezeichners durch die Art und Weise bestimmt, wie er verwendet wird.

1) Ein Bezeichner, der als Operand einer goto-Anweisung erscheint, wird im Label-Namensraum gesucht.
2) Ein Bezeichner, der auf das Schlüsselwort struct, union oder enum folgt, wird im Tag-Namensraum gesucht.
3) Ein Bezeichner, der auf den Member-Zugriffsoperator oder den Member-Zugriffsoperator über einen 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 einem Attributspezifizierer ([[...]]) erscheint, wird im globalen Attribut-Namensraum gesucht.
5) Ein Bezeichner, der auf das Token :: nach einem Attribut-Präfix folgt, wird im Namensraum gesucht, der durch das Attribut-Präfix eingeführt wird.
(seit C23)
6) Alle anderen Bezeichner werden im Namensraum der gewöhnlichen Bezeichner gesucht.

Inhalt

[bearbeiten] Hinweise

Die Namen von Makros sind keinem Namensraum zugeordnet, da sie vom Präprozessor vor der semantischen Analyse ersetzt werden.

Es ist üblich, Struktur-/Union-/Enum-Namen mithilfe einer typedef-Deklaration in den Namensraum der gewöhnlichen Bezeichner einzufügen.

struct A { };       // introduces the name A in tag name space
typedef struct A A; // first, lookup for A after "struct" finds one in tag name space
                    // then introduces the name A in the ordinary name space
struct A* p;        // OK, this A is looked up in the tag name space
A* q;               // OK, this A is looked up in the ordinary name space

Ein bekanntes Beispiel dafür, dass derselbe Bezeichner in zwei Namensräumen verwendet wird, ist der Bezeichner stat aus der POSIX-Headerdatei sys/stat.h. Er benennt eine Funktion, wenn er als gewöhnlicher Bezeichner verwendet wird, und bezeichnet eine Struktur, wenn er als Tag verwendet wird.

Im Gegensatz zu C++ sind Aufzählungskonstanten keine Struktur-Member, und ihr Namensraum ist der Namensraum der gewöhnlichen Bezeichner. Da es in C keinen Struktur-Scope gibt, ist ihr Scope der Scope, in dem die Strukturdeklaration erscheint.

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

Wenn ein Standardattribut, ein Attribut-Präfix oder ein nicht standardmäßiger Attributname nicht unterstützt wird, wird das ungültige Attribut selbst ignoriert, ohne einen Fehler zu verursachen.

(seit C23)

[bearbeiten] Beispiel

void foo (void) { return; } // ordinary name space, file scope
struct foo {      // tag name space, file scope
    int foo;      // member name space for this struct foo, file scope
    enum bar {    // tag name space, file scope
        RED       // ordinary name space, file scope
    } bar;        // member name space for this struct foo, file scope
    struct foo* p; // OK: uses tag/file scope name "foo"
};
enum bar x; // OK: uses tag/file-scope bar
// int foo; // Error: ordinary name space foo already in scope 
//union foo { int a, b; }; // Error: tag name space foo in scope
 
int main(void)
{
    goto foo; // OK uses "foo" from label name space/function scope
 
    struct foo { // tag name space, block scope (hides file scope)
       enum bar x; // OK, uses "bar" from tag name space/file scope
    };
    typedef struct foo foo; // OK: uses foo from tag name space/block scope
                            // defines block-scope ordinary foo (hides file scope)
    (foo){.x=RED}; // uses ordinary/block-scope foo and ordinary/file-scope RED
 
foo:; // label name space, function scope
}

[bearbeiten] 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

[bearbeiten] Siehe auch

C++ Dokumentation für Namensauflösung