Namensräume
Varianten
Aktionen

Gültigkeitsbereich

Von cppreference.com
< c‎ | Sprache

Jeder Bezeichner, der in einem C-Programm vorkommt, ist nur in einem möglicherweise diskontinuierlichen Teil des Quellcodes, der als sein Geltungsbereich bezeichnet wird, sichtbar (d. h. kann verwendet werden).

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

C hat vier Arten von Geltungsbereichen

  • Block-Geltungsbereich
  • Datei-Geltungsbereich
  • Funktions-Geltungsbereich
  • Funktionsprototyp-Geltungsbereich

Inhalt

[bearbeiten] Verschachtelte Geltungsbereiche

Wenn zwei verschiedene Entitäten, die durch denselben Bezeichner benannt werden, gleichzeitig im Geltungsbereich liegen und sie zum selben Namensraum gehören, sind die Geltungsbereiche verschachtelt (keine andere Form der Geltungsbereichsüberlappung ist zulässig), und die im inneren Geltungsbereich erscheinende Deklaration verbirgt die im äußeren Geltungsbereich erscheinende Deklaration.

// The name space here is ordinary identifiers.
 
int a;   // file scope of name a begins here
 
void f(void)
{
    int a = 1; // the block scope of the name a begins here; hides file-scope a
    {
      int a = 2;         // the scope of the inner a begins here, outer a is hidden
      printf("%d\n", a); // inner a is in scope, prints 2
    }                    // the block scope of the inner a ends here
    printf("%d\n", a);   // the outer a is in scope, prints 1
}                        // the scope of the outer a ends here
 
void g(int a);   // name a has function prototype scope; hides file-scope a

[bearbeiten] Block-Geltungsbereich

Der Geltungsbereich jedes Bezeichners, der innerhalb einer zusammengesetzten Anweisung deklariert wird, einschließlich Funktionskörpern, oder in jedem Ausdruck, jeder Deklaration oder jeder Anweisung, die in if, switch, for, while oder do-while-Anweisung vorkommt(seit C99), oder innerhalb der Parameterliste einer Funktionsdefinition beginnt am Punkt der Deklaration und endet am Ende des Blocks oder der Anweisung, in der er deklariert wurde.

void f(int n)  // scope of the function parameter 'n' begins
{         // the body of the function begins
   ++n;   // 'n' is in scope and refers to the function parameter
// int n = 2; // error: cannot redeclare identifier in the same scope
   for(int n = 0; n<10; ++n) { // scope of loop-local 'n' begins
       printf("%d\n", n); // prints 0 1 2 3 4 5 6 7 8 9
   } // scope of the loop-local 'n' ends
     // the function parameter 'n' is back in scope
   printf("%d\n", n); // prints the value of the parameter
} // scope of function parameter 'n' ends
int a = n; // Error: name 'n' is not in scope

Bis C99 stellten Auswahl- und Iterationsanweisungen keine eigenen Block-Geltungsbereiche auf (obwohl, wenn eine zusammengesetzte Anweisung in der Anweisung verwendet wurde, sie ihren üblichen Block-Geltungsbereich 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-Geltungsbereich-Variablen haben standardmäßig keine Linkage und automatische Speicherklasse. Beachten Sie, dass die Speicherklasse für lokale Nicht-VLA-Variablen beginnt, wenn der Block betreten wird, aber bis die Deklaration gesehen wird, ist die Variable nicht im Geltungsbereich und kann nicht zugegriffen werden.

[bearbeiten] Datei-Geltungsbereich

Der Geltungsbereich jedes Bezeichners, der außerhalb eines Blocks oder einer Parameterliste deklariert wird, beginnt am Punkt der Deklaration und endet am Ende der Translation Unit.

int i; // scope of i begins
static int g(int a) { return a; } // scope of g begins (note, "a" has block scope)
int main(void)
{
    i = g(2); // i and g are in scope
}

Datei-Geltungsbereich-Bezeichner haben standardmäßig externe Linkage und statische Speicherklasse.

[bearbeiten] Funktions-Geltungsbereich

Ein Label (und nur ein Label), das innerhalb einer Funktion deklariert wird, ist überall in dieser Funktion, in allen verschachtelten Blöcken, vor und nach seiner eigenen Deklaration im Geltungsbereich. 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 in scope even though declared later
label:;
   }
   goto label; // label ignores block scope
}
 
void g()
{
    goto label; // error: label not in scope in g()
}

[bearbeiten] Funktionsprototyp-Geltungsbereich

Der Geltungsbereich 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 is in scope and refers to the first parameter

Beachten Sie, dass, wenn es mehrere oder verschachtelte Deklaratoren in der Deklaration gibt, der Geltungsbereich am Ende des nächstgelegenen umschließenden Funktionsdeklarators endet.

void f ( // function name 'f' is at file scope
 long double f,            // the identifier 'f' is now in scope, file-scope 'f' is hidden
 char (**a)[10 * sizeof f] // 'f' refers to the first parameter, which is in scope
);
 
enum{ n = 3 };
int (*(*g)(int n))[n]; // the scope of the function parameter 'n'
                       // ends at the end of its function declarator
                       // in the array declarator, global n is in scope
// (this declares a pointer to function returning a pointer to an array of 3 int)

[bearbeiten] Punkt der Deklaration

Der Geltungsbereich 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 is in scope and refers to this struct
};

Der Geltungsbereich einer Aufzählungskonstante beginnt unmittelbar nach dem Erscheinen ihres definierenden Aufzählungselements in einer Aufzählungselementliste.

enum { x = 12 };
{
    enum { x = x + 1, // new x is not in scope until the comma, x is initialized to 13
           y = x + 1  // the new enumerator x is now in scope, y is initialized to 14
         };
}

Der Geltungsbereich jedes anderen Bezeichners beginnt unmittelbar nach dem Ende seines Deklarators und vor dem Initialisierer, falls vorhanden.

int x = 2; // scope of the first 'x' begins
{
    int x[x]; // scope of the newly declared x begins after the declarator (x[x]).
              // Within the declarator, the outer 'x' is still in scope.
              // This declares a VLA array of 2 int.
}
unsigned char x = 32; // scope of the outer 'x' begins
{
    unsigned char x = x;
            // scope of the inner 'x' begins before the initializer (= x)
            // this does not initialize the inner 'x' with the value 32, 
            // this initializes the inner 'x' with its own, indeterminate, value
}
 
unsigned long factorial(unsigned long n)
// declarator ends, 'factorial' is in scope from this point
{
   return n<2 ? 1 : n*factorial(n-1); // recursive call
}

Als Sonderfall gilt, dass der Geltungsbereich eines Typnamens, der keine Deklaration eines Bezeichners ist, unmittelbar nach der Stelle innerhalb des Typnamens beginnt, an der der Bezeichner erscheinen würde, wenn er nicht weggelassen worden wäre.

[bearbeiten] Hinweise

Vor C89 hatten Bezeichner mit externer Linkage Datei-Geltungsbereiche, auch wenn sie innerhalb eines Blocks eingeführt wurden. Aus diesem Grund ist ein C89-Compiler nicht verpflichtet, die Verwendung eines externen Bezeichners zu diagnostizieren, der aus dem Geltungsbereich herausgefallen ist (eine solche Verwendung ist undefiniertes Verhalten).

Lokale Variablen innerhalb des Schleifenkörpers können Variablen, die in der Initialisierungsklausel einer for-Schleife deklariert wurden, in C (ihr Geltungsbereich ist verschachtelt) verdecken, aber in C++ nicht.

Im Gegensatz zu C++ hat C keinen Struktur-Geltungsbereich: Namen, die innerhalb einer Struktur-/Union-/Aufzählung-Deklaration deklariert werden, befinden sich im selben Geltungsbereich wie die Strukturdeklaration (außer dass Datenelemente ihren eigenen Member-Namensraum haben).

struct foo {
    struct baz {};
    enum color {RED, BLUE};
};
struct baz b; // baz is in scope
enum color x = RED; // color and RED are in scope

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

[bearbeiten] Siehe auch

C++-Dokumentation für Geltungsbereich