Names are used to identify types, objects and variables, macros, and functions in C. Every name belongs to a namespace. Two identical names in distinct namespaces are distinct names. Most names follow the grammar of identifier.

identifier
identifier-nondigit
identifier identifier-nondigit
identifier digit
identifier-nondigit
nondigit
universal-character-name
other implementation-defined characters
nondigit
any of _ a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
digit
any of 0 1 2 3 4 5 6 7 8 9
universal-character-name
\u hex-quad
\U hex-quad hex-quad
hex-quad
hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit
hexadecimal-digit
any of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
identifier-list
identifier
identifier-list , identifier

Each structure type and union type has its own namespace, in which the names of its members belong. The names of some types follow struct-or-union-specifier or enum-specifier, which share a distinct namespace, so struct foo and foo are distinct.

struct-or-union-specifier
struct-or-union identifier
struct-or-union
struct
union
enum-specifier
enum identifier

Declarations

Declarations are constructs in a program that state that a name identifies an object, type or function, and describe that entity. Every declaration has a scope, which indicates in which lexical portion of a source file the declared name has its declared meaning.

translation-unit
external-declaration
translation-unit external-declaration
external-declaration
function-definition
declaration
declaration
declaration-specifiers init-declarator-listopt
static_assert-declaration
since C11
declaration-specifiers
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt
storage-class-specifier
typedef
extern
static
_Thread_local
auto
register
init-declarator-list
init-declarator
init-declarator-list , init-declarator
init-declarator
declarator
declarator = initializer
declarator
pointeropt direct-declarator
direct-declarator
identifier
( declarator )
direct-declarator [ type-qualifier-listopt assignment-expressionopt ]
direct-declarator [ static type-qualifier-listopt assignment-expression ]
direct-declarator [ type-qualifier-list static assignment-expression ]
direct-declarator [ type-qualifier-listopt * ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-listopt )
The pre-standard way
initializer
assignment-expression
{ initializer-list }
{ initializer-list , }
since C99
initializer-list
designationopt initializer
initializer-list , designationopt initializer
designation
designator-list =
designator-list
designator
designator-list designator
designator
[ constant-expression ]
. identifier

Scope

A single name does not always mean the same thing in all contexts. The lexical context in which a name has a given meaning is called its scope.

Variables, types and functions declared inside a block statement have block scope; the declared name only identifies that entity from a point just after the declaration until the end of the block. Other blocks within the block could declare the same name to identify a different entity, hiding the outer meaning until the end of the inner block.

Declaration scope is similar, and applies to names declared within function declarations. For example, this declaration (which is also a function definition) declares two parameters ap and bp, whose scopes extend to the end of the definition:

void swap(int *ap, int *bp)
{
  int tmp = *ap;
  *ap = *bp;
  *bp = tmp;
}

The declaration scopes of ap and bp are almost the same as the block scope of tmp, starting only a little earlier, and ending at the same place. This is of no consequence in that example, but it is relevant when declaring a function taking a multidimensional array as one argument, and a dimension of that array as another:

double sum(int h, int w, double arr[h][w]);

The declarations of h and w must come before arr so that it falls within their scopes.

Declaration scope is also important when structure types, union types and enumeration types appear in function declarations. For example, in this declaration:

void foo(struct bar *bp);

…the name struct bar is only in scope until the end of the prototype. Any references to struct bar after that point will be considered to refer to a different type. This problem does not occur if struct bar was already declared independently before the prototype, however.

Lastly, there is file scope, which lasts from the point of declaration to the end of the translation unit. Names of objects, types and functions with file scope can be hidden locally by identical names declared with declaration or block scope. All macros effectively have file scope, as they are resolved by the preprocessor which has no notion of scope. For the same reason, they also cannot be hidden by inner scopes.


CHaR
Sitemap Supported
Site format updated 2024-06-05T22:37:07.391+0000
Data updated 1970-01-01T00:00:00.000+0000
Page updated 2022-06-17T21:43:05.000+0000