When an identifier is encountered in a C program, a lookup is performed to locate the declaration that introduced that identifier and that is currently in scope. C allows more than one declaration for the same identifier to be in scope simultaneously if these identifiers belong to different categories, called name spaces:
At the point of lookup, the name space of an identifier is determined by the manner in which it is used:
struct
, union
, or enum
is looked up in the tag name space.Notes
The names of macros are not part of any name space because they are replaced by the preprocessor prior to semantic analysis.
It is common practice to inject struct/union/enum names into the name space of the ordinary identifiers using a typedef declaration:
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
A well-known example of the same identifier being used across two name spaces is the identifier stat
from the POSIX header sys/stat.h
. It names a function when used as an ordinary identifier and indicates a struct when used as a tag.
Unlike in C++, enumeration constants are not struct members, and their name space is the name space of ordinary identifiers, and since there is no struct scope in C, their scope is the scope in which the struct declaration appears:
struct tagged_union { enum {INT, FLOAT, STRING} type; int integer; float floating_point; char *string; } tu; tu.type = INT; // OK in C, error in C++
Example
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 }
References
- C11 standard (ISO/IEC 9899:2011):
- 6.2.3 Name spaces of identifiers (p: 37)
- C99 standard (ISO/IEC 9899:1999):
- 6.2.3 Name spaces of identifiers (p: 31)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.1.2.3 Name spaces of identifiers
See Also
C++ documentation for Name lookup |
Please login to continue.