Namespaces
Variants

Lookup and name spaces

From cppreference.net

Когда в программе на C встречается идентификатор , выполняется поиск для нахождения объявления , которое ввело этот идентификатор и которое в данный момент находится в области видимости . C позволяет нескольким объявлениям одного идентификатора одновременно находиться в области видимости, если эти идентификаторы принадлежат к разным категориям, называемым пространствами имён :

1) Пространство имён меток: все идентификаторы, объявленные как labels .
2) Имена тегов: все идентификаторы, объявленные как имена structs , unions и enumerated types . Отметим, что все три вида тегов используют одно пространство имён.
3) Имена членов: все идентификаторы, объявленные как члены любой struct или union . Каждая struct и union вводит собственное пространство имён такого типа.
4) Пространство имен глобальных атрибутов: токены атрибутов определенные стандартом или префиксы атрибутов, определенные реализацией.
5) Нестандартные имена атрибутов: имена атрибутов, следующие за префиксами атрибутов. Каждый префикс атрибута имеет отдельное пространство имен для определяемых реализацией атрибутов, которые он вводит.
(since C23)
6) Все остальные идентификаторы, называемые обычными идентификаторами для отличия от (1-5) (имена функций, имена объектов, имена typedef, константы перечислений).

В момент поиска пространство имён идентификатора определяется способом его использования:

1) идентификатор, появляющийся в качестве операнда оператора goto , ищется в пространстве имён меток.
2) идентификатор, следующий за ключевым словом struct , union , или enum , ищется в пространстве имен тегов.
3) идентификатор, следующий за оператором доступа к члену или оператором доступа к члену через указатель, ищется в пространстве имен членов типа, определяемого левым операндом оператора доступа к члену.
4) идентификатор, который непосредственно появляется в спецификаторе атрибута ( [ [ ... ] ] ), ищется в глобальном пространстве имен атрибутов.
5) идентификатор, следующий за токеном :: после префикса атрибута, ищется в пространстве имен, введенном префиксом атрибута.
(since C23)
6) все остальные идентификаторы ищутся в пространстве имён обычных идентификаторов.

Содержание

Примечания

Имена макросов не принадлежат какому-либо пространству имён, поскольку они заменяются препроцессором до семантического анализа.

Обычной практикой является внедрение имён структур/объединений/перечислений в пространство имён обычных идентификаторов с помощью typedef объявления:

struct A { };       // вводит имя A в пространстве имен тегов
typedef struct A A; // сначала поиск A после "struct" находит его в пространстве имен тегов
                    // затем вводит имя A в обычном пространстве имен
struct A* p;        // OK, этот A ищется в пространстве имен тегов
A* q;               // OK, этот A ищется в обычном пространстве имен

Хорошо известным примером использования одного и того же идентификатора в двух пространствах имён является идентификатор stat из заголовка POSIX sys/stat.h . Он обозначает функцию при использовании в качестве обычного идентификатора и указывает на структуру при использовании в качестве тега.

В отличие от C++, константы перечисления не являются членами структуры, их пространство имён — это пространство имён обычных идентификаторов, и поскольку в C нет области видимости структуры, их область видимости — это область видимости, в которой появляется объявление структуры:

struct tagged_union {
   enum {INT, FLOAT, STRING} type;
   union {
      int integer;
      float floating_point;
      char *string;
   };
} tu;
tu.type = INT; // Корректно в C, ошибка в C++

Если стандартный атрибут, префикс атрибута или нестандартное имя атрибута не поддерживается, сам некорректный атрибут игнорируется без вызова ошибки.

(since C23)

Пример

void foo (void) { return; } // обычное пространство имен, область видимости файла
struct foo {      // пространство имен тегов, область видимости файла
    int foo;      // пространство имен членов для этой struct foo, область видимости файла
    enum bar {    // пространство имен тегов, область видимости файла
        RED       // обычное пространство имен, область видимости файла
    } bar;        // пространство имен членов для этой struct foo, область видимости файла
    struct foo* p; // OK: использует имя "foo" из пространства тегов/области файла
};
enum bar x; // OK: использует bar из пространства тегов/области файла
// int foo; // Ошибка: обычное пространство имен foo уже в области видимости
//union foo { int a, b; }; // Ошибка: пространство имен тегов foo в области видимости
int main(void)
{
    goto foo; // OK использует "foo" из пространства имен меток/области функции
    struct foo { // пространство имен тегов, область блока (скрывает область файла)
       enum bar x; // OK, использует "bar" из пространства имен тегов/области файла
    };
    typedef struct foo foo; // OK: использует foo из пространства имен тегов/области блока
                            // определяет обычное foo в области блока (скрывает область файла)
    (foo){.x=RED}; // использует обычное/блочное foo и обычное/файловое RED
foo:; // пространство имен меток, область функции
}

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
  • 6.2.3 Пространства имён идентификаторов (стр: 29-30)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 6.2.3 Пространства имён идентификаторов (стр: 37)
  • Стандарт C99 (ISO/IEC 9899:1999):
  • 6.2.3 Пространства имён идентификаторов (стр: 31)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
  • 3.1.2.3 Пространства имён идентификаторов

Смотрите также

Документация C++ для Поиска имён