Spec-Zone.ru › C

Пространства имён поиска и имён

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

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

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

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

Примечания

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

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

struct A { };       // introduces the name A in tag name space
typedef struct A A; // first, lookup for A after "struct" finds one in tag name space
                    // then introduces the name A in the ordinary name space
struct A* p;        // OK, this A is looked up in the tag name space
A* q;               // OK, this A is looked up in the ordinary name space

Известным примером одного и того же идентификатора, используемого в двух пространствах имён, является идентификатор 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; // OK in C, error in C++

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

(с C23)

Пример

void foo (void) { return; } // ordinary name space, file scope
struct foo {      // tag name space, file scope
    int foo;      // member name space for this struct foo, file scope
    enum bar {    // tag name space, file scope
        RED       // ordinary name space, file scope
    } bar;        // member name space for this struct foo, file scope
    struct foo* p; // OK: uses tag/file scope name "foo"
};
enum bar x; // OK: uses tag/file-scope bar
// int foo; // Error: ordinary name space foo already in scope 
//union foo { int a, b; }; // Error: tag name space foo in scope
 
int main(void)
{
    goto foo; // OK uses "foo" from label name space/function scope
 
    struct foo { // tag name space, block scope (hides file scope)
       enum bar x; // OK, uses "bar" from tag name space/file scope
    };
    typedef struct foo foo; // OK: uses foo from tag name space/block scope
                            // defines block-scope ordinary foo (hides file scope)
    (foo){.x=RED}; // uses ordinary/block-scope foo and ordinary/file-scope RED
 
foo:; // label name space, function scope
}

Ссылки

  • Стандарт 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++ для Поиск имён

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

Spec-Zone.ru

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