Spec-Zone.ru › C

Область видимости

Каждый идентификатор, встречающийся в программе на C, является видимым (то есть может быть использован) только в некоторой, возможно несвязной, части исходного кода, называемой его областью видимости.

В пределах одной области видимости идентификатор может обозначать более одной сущности только в том случае, если эти сущности находятся в разных пространствах имён.

В C существует четыре вида областей видимости:

  • область видимости блока
  • область видимости файла
  • область видимости функции
  • область видимости прототипа функции

Вложенные области видимости

Если две разные сущности, обозначенные одним и тем же идентификатором, одновременно находятся в области видимости и принадлежат одному и тому же пространству имён, области видимости являются вложенными (перекрытие областей видимости других видов не допускается), а объявление во внутренней области видимости скрывает объявление во внешней области видимости:

// 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

Область видимости блока

Область видимости любого идентификатора, объявленного внутри составного оператора, включая тела функций, или в любом выражении, объявлении либо операторе, входящем в оператор if, switch, for, while или do-while(начиная с C99), либо в списке параметров определения функции, начинается в точке объявления и заканчивается в конце блока или оператора, в котором он был объявлен.

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

До C99 операторы выбора и циклы не создавали собственных областей видимости блоков (хотя составной оператор, использованный в таком операторе, имел обычную область видимости блока):

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
}
(начиная с C99)

Переменные с областью видимости блока по умолчанию имеют отсутствие связывания и автоматическую длительность хранения. Обратите внимание: длительность хранения локальных переменных, не являющихся VLA, начинается при входе в блок, но до появления объявления переменная не находится в области видимости и к ней нельзя обратиться.

Область видимости файла

Область видимости любого идентификатора, объявленного вне любого блока или списка параметров, начинается в точке объявления и заканчивается в конце единицы трансляции.

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
}

Идентификаторы с областью видимости файла по умолчанию имеют внешнее связывание и статическую длительность хранения.

Область видимости функции

Метка (и только метка), объявленная внутри функции, находится в области видимости во всей этой функции, во всех вложенных блоках, как до, так и после собственного объявления. Примечание: метка объявляется неявно — для этого перед двоеточием и любым оператором используется идентификатор, который иначе нигде не используется.

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()
}

Область видимости прототипа функции

Область видимости имени, введённого в списке параметров объявления функции, не являющегося определением, заканчивается в конце декларатора функции.

int f(int n,
      int a[n]); // n is in scope and refers to the first parameter

Обратите внимание: если в объявлении имеется несколько или вложенных деклараторов, область видимости заканчивается в конце ближайшего внешнего декларатора функции:

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)

Точка объявления

Область видимости тегов структур, объединений и перечислений начинается сразу после появления тега в спецификаторе типа, объявляющем этот тег.

struct Node {
   struct Node* next; // Node is in scope and refers to this struct
};

Область видимости константы перечисления начинается сразу после появления соответствующего элемента перечисления в списке перечислителей.

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
         };
}

Область видимости любого другого идентификатора начинается сразу после конца его декларатора и до инициализатора, если он есть:

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
}

В особом случае область видимости имени типа, которое не является объявлением идентификатора, считается начинающейся сразу после места в имени типа, где находился бы идентификатор, если бы его не опустили.

Примечания

До C89 идентификаторы с внешним связыванием имели область видимости файла, даже если вводились внутри блока. Поэтому компилятор C89 не обязан диагностировать использование идентификатора с классом хранения extern, вышедшего из области видимости (такое использование является неопределённым поведением).

Локальные переменные внутри тела цикла могут скрывать переменные, объявленные в части инициализации цикла for в C (их области видимости вложены), но в C++ этого делать нельзя.

В отличие от C++, в C нет области видимости структуры: имена, объявленные внутри объявления структуры/объединения/перечисления, находятся в той же области видимости, что и объявление структуры (за исключением того, что поля данных находятся в собственном пространстве имён членов):

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

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
    • 6.2.1 Области видимости идентификаторов, имён типов и составных литералов (стр.: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.2.1 Области видимости идентификаторов (стр.: 28–29)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.2.1 Области видимости идентификаторов (стр.: 35–36)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.2.1 Области видимости идентификаторов (стр.: 29–30)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.1.2.1 Области видимости идентификаторов

См. также

Документация по C++ для области видимости

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/scope

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API