liveBook · Manning

Identifier

As explained in Modern C

An identifier is a C name assigned to a program entity such as an object, type alias, function, or constant.

Consider three C declarations: `int main(void);`, `double A[5];`, and `size_t i;`. The names `main`, `A`, and `i` are identifiers. The surrounding syntax says what each name represents: a function, an array, and an object of type `size_t`, respectively. section 2.2

int main(void);
double A[5];
size_t i;


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":3}],[{\"line\":0,\"ch\":4},{\"line\":0,\"ch\":8}],[{\"line\":0,\"ch\":9},{\"line\":0,\"ch\":13}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":6}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":6}]]"}
!@%STYLE%@!

Compare the parentheses, brackets, and plain object declaration. Each declaration gives the compiler properties of a name; these lines alone do not define the function or initialize the objects. section 2.2

An identifier is a name given to a program entity. Identifiers can name data objects, type aliases, functions, and constants. `A` and `i` name objects; `size_t` names a type alias; `main` and `printf` name functions; and `EXIT_SUCCESS` is a named constant. Unlike a literal such as `0`, an identifier does not itself spell out a fixed value. section 2.1

TAKEAWAY: A name is not the thing it names. Keep these distinctions in view:

  • Declare an identifier before using it so the compiler knows its properties. Keywords are predefined by the language and cannot be declared or redefined as identifiers. section 2.2
  • Distinguish an object's identifier from its type and value. An object definition specifies where that object comes to be; a declaration specifies properties associated with its name. section 2.2 section 2.5
  • An identifier is visible only within its scope, starting at its declaration. A declaration of the same name in a subordinate scope can shadow it without making the earlier object unusable. section 13.2
  • In a preprocessor condition, an unknown identifier evaluates to `0`. This is a special rule for such conditions, not a substitute for declaring identifiers used in C code. section 8.1.5 section 2.2

One spelling, two objects

In the `extern` example, file-scope `i` is initialized to `1`, while a local `i` is initialized to `2`. The local definition creates a distinct object. Inside the `if`, `extern unsigned i;` refers back to the file-scope object, so the program prints `1`. Reading the spelling alone is not enough: check the declaration and scope that govern each use. section 13.2

Listing 13.2. An example of shadowing with an extern variable
 1   #include <stdio.h>
 2
 3   unsigned i = 1;
 4
 5   int main(void) {
 6     unsigned i = 2;        /* A new object */ 
 7     if (i) {
 8       extern unsigned i;   /* An existing object */ 
 9       printf("%u\n", i);
10     } else {
11       printf("%u\n", i);
12     }
13   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":1},{\"line\":0,\"ch\":2}],[{\"line\":2,\"ch\":18},{\"line\":2,\"ch\":19}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":1}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":1}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":1}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":1}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":13}],[{\"line\":1,\"ch\":1},{\"line\":1,\"ch\":2}],[{\"line\":5,\"ch\":20},{\"line\":5,\"ch\":21}],[{\"line\":11,\"ch\":1},{\"line\":11,\"ch\":2}],[{\"line\":2,\"ch\":1},{\"line\":2,\"ch\":2}],[{\"line\":12,\"ch\":1},{\"line\":12,\"ch\":2}],[{\"line\":2,\"ch\":5},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":15}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":24}],[{\"line\":3,\"ch\":1},{\"line\":3,\"ch\":2}],[{\"line\":4,\"ch\":1},{\"line\":4,\"ch\":2}],[{\"line\":4,\"ch\":5},{\"line\":4,\"ch\":8}],[{\"line\":8,\"ch\":11},{\"line\":8,\"ch\":14}],[{\"line\":10,\"ch\":11},{\"line\":10,\"ch\":14}],[{\"line\":4,\"ch\":9},{\"line\":4,\"ch\":13}],[{\"line\":4,\"ch\":14},{\"line\":4,\"ch\":18}],[{\"line\":5,\"ch\":1},{\"line\":5,\"ch\":2}],[{\"line\":2,\"ch\":5},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":15}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":24}],[{\"line\":6,\"ch\":1},{\"line\":6,\"ch\":2}],[{\"line\":6,\"ch\":7},{\"line\":6,\"ch\":9}],[{\"line\":7,\"ch\":1},{\"line\":7,\"ch\":2}],[{\"line\":7,\"ch\":9},{\"line\":7,\"ch\":24}],[{\"line\":8,\"ch\":1},{\"line\":8,\"ch\":2}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":10,\"ch\":9},{\"line\":10,\"ch\":15}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":2}],[{\"line\":9,\"ch\":9},{\"line\":9,\"ch\":13}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":10,\"ch\":9},{\"line\":10,\"ch\":15}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":2}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":2}]]"}
!@%STYLE%@!

Trace each occurrence of `i` through the file-scope definition, local definition, and inner `extern` declaration to check which object is printed. section 13.2

Choose a consistent naming policy, but check technical restrictions before debating style. C reserves some identifiers, including names with certain leading-underscore patterns; standard-library and file-scope names carry further restrictions. Header-visible names deserve particular care because macros and later platform changes can expose collisions. Expose as few names globally as an interface needs. section 9.2

How Modern C covers it

How deep it goes
Defines identifier roles, works through declarations, then examines naming restrictions and shadowing; does not enumerate all name-space rules.
Examples
Uses function, array, and object declarations; a header-name collision scenario; and an `extern` shadowing program.
What it assumes
Introduces identifier roles and declaration syntax through small C examples while assuming familiarity with reading basic program statements.
What you can do after
Diagnose/debug with it by tracing a name to its declaration and scope, and avoid reserved or collision-prone names.
How it connects
Connects identifiers to declarations, definitions, types, scope, shadowing, macros, and preprocessor conditions.

Also explained in

Compare how 5 books explain identifier →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.