Namespaces
Variants

Scope

From cppreference.net

Jeder Bezeichner , der in einem C-Programm erscheint, ist sichtbar (das heißt, kann verwendet werden) nur in einem möglicherweise nicht zusammenhängenden Teil des Quellcodes, der seinen Gültigkeitsbereich genannt wird.

Innerhalb eines Gültigkeitsbereichs darf ein Bezeichner mehr als eine Entität bezeichnen, nur wenn die Entitäten in verschiedenen Namensräumen liegen.

C hat vier Arten von Gültigkeitsbereichen:

  • Block-Bereich
  • Dateibereich
  • Funktionsbereich
  • Funktionsprototyp-Bereich

Inhaltsverzeichnis

Verschachtelte Gültigkeitsbereiche

Wenn zwei verschiedene Entitäten, die durch denselben Bezeichner benannt sind, gleichzeitig im Gültigkeitsbereich sind und sie zum selben Namensraum gehören, sind die Gültigkeitsbereiche verschachtelt (keine andere Form von Bereichsüberlappung ist erlaubt), und die Deklaration, die im inneren Bereich erscheint, verbirgt die Deklaration, die im äußeren Bereich erscheint:

// Der Namensraum hier besteht aus gewöhnlichen Bezeichnern.
int a;   // Dateibereich des Namens a beginnt hier
void f(void)
{
    int a = 1; // Der Blockbereich des Namens a beginnt hier; verdeckt den Dateibereich-a
    {
      int a = 2;         // Der Bereich des inneren a beginnt hier, äußeres a wird verdeckt
      printf("%d\n", a); // Inneres a ist im Gültigkeitsbereich, gibt 2 aus
    }                    // Der Blockbereich des inneren a endet hier
    printf("%d\n", a);   // Das äußere a ist im Gültigkeitsbereich, gibt 1 aus
}                        // Der Bereich des äußeren a endet hier
void g(int a);   // Name a hat Funktionsprototyp-Bereich; verdeckt Dateibereich-a

Blockgültigkeitsbereich

Der Gültigkeitsbereich eines jeden Bezeichners, der innerhalb eines Verbundstatements , einschließlich Funktionsrümpfen, oder in einem Ausdruck, einer Deklaration oder einer Anweisung, die in if -, switch -, for -, while - oder do-while -Anweisungen vorkommt (seit C99) , oder innerhalb der Parameterliste einer Funktionsdefinition deklariert wird, beginnt am Punkt der Deklaration und endet am Ende des Blocks oder der Anweisung, in dem er deklariert wurde.

void f(int n)  // Gültigkeitsbereich des Funktionsparameters 'n' beginnt
{         // der Körper der Funktion beginnt
   ++n;   // 'n' ist im Gültigkeitsbereich und bezieht sich auf den Funktionsparameter
// int n = 2; // Fehler: Kann Bezeichner im selben Gültigkeitsbereich nicht erneut deklarieren
   for(int n = 0; n<10; ++n) { // Gültigkeitsbereich der schleifenlokalen 'n' beginnt
       printf("%d\n", n); // gibt 0 1 2 3 4 5 6 7 8 9 aus
   } // Gültigkeitsbereich der schleifenlokalen 'n' endet
     // der Funktionsparameter 'n' ist wieder im Gültigkeitsbereich
   printf("%d\n", n); // gibt den Wert des Parameters aus
} // Gültigkeitsbereich des Funktionsparameters 'n' endet
int a = n; // Fehler: Name 'n' ist nicht im Gültigkeitsbereich

Bis C99 führten Auswahl- und Iterationsanweisungen keinen eigenen Blockgültigkeitsbereich ein (obwohl, wenn eine zusammengesetzte Anweisung in der Anweisung verwendet wurde, sie ihren üblichen Blockgültigkeitsbereich hatte):

enum {a, b};
int different(void)
{
    if (sizeof(enum {b, a}) != sizeof(int))
        return a; // a == 1
    return b; // b == 0 in C89, b == 1 in C99
}
(seit C99)

Block-Bereich-Variablen haben standardmäßig keine Bindung und automatische Speicherdauer . Beachten Sie, dass die Speicherdauer für nicht-VLA-Lokale Variablen beginnt, wenn der Block betreten wird, aber bis die Deklaration gesehen wird, ist die Variable nicht im Gültigkeitsbereich und kann nicht zugegriffen werden.

Dateibereich

Der Gültigkeitsbereich eines jeden Bezeichners, der außerhalb eines Blocks oder einer Parameterliste deklariert wird, beginnt an der Stelle seiner Deklaration und endet am Ende der Übersetzungseinheit.

int i; // Gültigkeitsbereich von i beginnt
static int g(int a) { return a; } // Gültigkeitsbereich von g beginnt (Hinweis: "a" hat Blockgültigkeitsbereich)
int main(void)
{
    i = g(2); // i und g sind im Gültigkeitsbereich
}

Dateibereichs-Identifikatoren haben standardmäßig externe Bindung und statische Speicherdauer .

Funktionsbereich

Ein Label (und nur ein Label) , das innerhalb einer Funktion deklariert wird, ist überall in dieser Funktion gültig, in allen geschachtelten Blöcken, sowohl vor als auch nach seiner eigenen Deklaration. Hinweis: Ein Label wird implizit deklariert, indem ein ansonsten ungenutzter Bezeichner vor dem Doppelpunkt vor einer beliebigen Anweisung verwendet wird.

void f()
{
   {   
       goto label; // Label im Gültigkeitsbereich, obwohl später deklariert
label:;
   }
   goto label; // Label ignoriert Blockgültigkeitsbereich
}
void g()
{
    goto label; // Fehler: Label nicht im Gültigkeitsbereich in g()
}

Funktionsprototyp-Bereich

Der Gültigkeitsbereich eines Namens, der in der Parameterliste einer Funktionsdeklaration eingeführt wird, die keine Definition ist, endet am Ende des Funktions- Deklarators .

int f(int n,
      int a[n]); // n ist im Gültigkeitsbereich und bezieht sich auf den ersten Parameter

Beachten Sie, dass bei mehreren oder geschachtelten Deklaratoren in der Deklaration der Gültigkeitsbereich am Ende des nächstgelegenen umschließenden Funktionsdeklarators endet:

void f ( // Funktionsname 'f' befindet sich im Dateibereich
 long double f,            // der Bezeichner 'f' ist jetzt im Gültigkeitsbereich, Dateibereich-'f' ist verborgen
 char (**a)[10 * sizeof f] // 'f' bezieht sich auf den ersten Parameter, der im Gültigkeitsbereich liegt
);
enum{ n = 3 };
int (*(*g)(int n))[n]; // der Gültigkeitsbereich des Funktionsparameters 'n'
                       // endet am Ende seines Funktionsdeklarators
                       // im Arraydeklarator ist globales n im Gültigkeitsbereich
// (dies deklariert einen Zeiger auf eine Funktion, die einen Zeiger auf ein Array von 3 int zurückgibt)

Punkt der Deklaration

Der Gültigkeitsbereich von Struktur-, Union- und Aufzählungstags beginnt unmittelbar nach dem Erscheinen des Tags in einem Typspezifizierer, der das Tag deklariert.

struct Node {
   struct Node* next; // Node ist im Gültigkeitsbereich und bezieht sich auf dieses struct
};

Der Gültigkeitsbereich einer Aufzählungskonstante beginnt unmittelbar nach dem Erscheinen ihres definierenden Enumerators in einer Enumeratorliste.

enum { x = 12 };
{
    enum { x = x + 1, // neues x ist erst nach dem Komma im Gültigkeitsbereich, x wird mit 13 initialisiert
           y = x + 1  // der neue Aufzähler x ist jetzt im Gültigkeitsbereich, y wird mit 14 initialisiert
         };
}

Der Gültigkeitsbereich eines jeden anderen Bezeichners beginnt direkt nach dem Ende seines Deklarators und vor dem Initialisierer, falls vorhanden:

int x = 2; // Gültigkeitsbereich des ersten 'x' beginnt
{
    int x[x]; // Gültigkeitsbereich des neu deklarierten x beginnt nach dem Deklarator (x[x]).
              // Innerhalb des Deklarators ist das äußere 'x' weiterhin im Gültigkeitsbereich.
              // Dies deklariert ein VLA-Array von 2 int.
}
unsigned char x = 32; // Gültigkeitsbereich des äußeren 'x' beginnt
{
    unsigned char x = x;
            // Gültigkeitsbereich des inneren 'x' beginnt vor dem Initialisierer (= x)
            // dies initialisiert das innere 'x' nicht mit dem Wert 32,
            // dies initialisiert das innere 'x' mit seinem eigenen, unbestimmten Wert
}
unsigned long factorial(unsigned long n)
// Deklarator endet, 'factorial' ist ab diesem Punkt im Gültigkeitsbereich
{
   return n<2 ? 1 : n*factorial(n-1); // rekursiver Aufruf
}

Als Sonderfall wird der Gültigkeitsbereich eines Typnamens , der keine Deklaration eines Identifikators ist, so betrachtet, dass er genau an der Stelle innerhalb des Typnamens beginnt, an der der Identifikator erscheinen würde, wenn er nicht ausgelassen worden wäre.

Hinweise

Vor C89 hatten Bezeichner mit externer Verknüpfung Dateigültigkeitsbereich, selbst wenn sie innerhalb eines Blocks eingeführt wurden, und aus diesem Grund ist ein C89-Compiler nicht verpflichtet, die Verwendung eines extern-Bezeichners zu diagnostizieren, der außerhalb des Gültigkeitsbereichs liegt (eine solche Verwendung ist undefiniertes Verhalten).

Lokale Variablen innerhalb eines Schleifenkörpers können in C Variablen verbergen, die in der Init-Klausel einer for -Schleife deklariert wurden (deren Gültigkeitsbereich ist verschachtelt), können dies jedoch in C++ nicht tun.

Im Gegensatz zu C++ hat C keinen Strukturbereich: Namen, die innerhalb einer Struktur-/Union-/Enum-Deklaration deklariert werden, befinden sich im selben Bereich wie die Strukturdeklaration (mit der Ausnahme, dass Datenelemente in ihrem eigenen Elementnamenraum liegen):

struct foo {
    struct baz {};
    enum color {RED, BLUE};
};
struct baz b; // baz ist im Gültigkeitsbereich
enum color x = RED; // color und RED sind im Gültigkeitsbereich

Referenzen

  • C23-Standard (ISO/IEC 9899:2024):
  • 6.2.1 Geltungsbereiche von Bezeichnern, Typnamen und zusammengesetzten Literalen (S.: TBD)
  • C17-Standard (ISO/IEC 9899:2018):
  • 6.2.1 Geltungsbereiche von Bezeichnern (S. 28-29)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.2.1 Geltungsbereiche von Bezeichnern (S. 35-36)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.2.1 Geltungsbereiche von Bezeichnern (S. 29-30)
  • C89/C90-Standard (ISO/IEC 9899:1990):
  • 3.1.2.1 Geltungsbereiche von Bezeichnern

Siehe auch