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)

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

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

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

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: имена, объявленные внутри объявления struct/union/enum, находятся в той же области видимости, что и объявление struct (за исключением того, что члены данных находятся в своём собственном пространстве имён членов):

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

Ссылки

  • Стандарт 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/w/c/language/scope

Spec-Zone.ru

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