Interview Questions

How can I determine which identifiers are safe for me to use and which are reserved?

C Interview Questions and Answers


(Continued from previous question...)

How can I determine which identifiers are safe for me to use and which are reserved?

Namespace management can be a sticky issue. The problem--which isn't always obvious--is that you don't want to pick identifiers already in use by the implementation, such that you get ``multiply defined'' errors or--even worse--quietly replace one of the implementation's symbols and break everything. You also want some guarantee that later releases won't usurp names you're legitimately using. (Few things are more frustrating than taking a debugged, working, production program, recompiling it under a new release of a compiler, and having the build fail due to namespace or other problems.) Therefore, the ANSI/ISO C Standard contains rather elaborate definitions carving out distinct namespace subsets for the user and the implementation.

To make sense of ANSI's rules, and before we can say whether a given identifier is reserved, we must understand three attributes of the identifier: its scope, namespace, and linkage.

There are four kinds of scope (regions over which an identifier's declaration is in effect) in C: function, file, block, and prototype. (The fourth one exists only in the parameter lists of function prototype declarations;)

There are four different kinds of namespaces, for:
* labels (i.e. goto targets);
* tags (names of structures, unions, and enumerations; these three aren't separate even though they theoretically could be);
* structure/union members (one namespace per structure or union); and
* everything else (functions, variables, typedef names, enumeration constants), termed ``ordinary identifiers'' by the Standard.

Another set of names (though not termed a ``namespace'' by the Standard) consists of preprocessor macros; these are all expanded before the compiler gets around to considering the four formal namespaces.

The standard defines three kinds of ``linkage'': external, internal, and none. For our purposes, external linkage means global, non-static variables and functions (across all source files), internal linkage means static variables and functions with file scope, and ``no linkage'' refers to local variables, and also things like typedef names and enumeration constants.

The rules, paraphrased from ANSI, are:
* 1. All identifiers beginning with an underscore followed by an upper-case letter or another underscore are always reserved (all scopes, all namespaces).
* 2. All identifiers beginning with an underscore are reserved for ordinary identifiers (functions, variables, typedefs, enumeration constants) with file scope.
* 3. A macro name defined in a standard header is reserved for any use if any header which #defines it is #included.
* 4. All standard library identifiers with external linkage (e.g. function names) are always reserved as identifiers with external linkage.
* 5. Typedef and tag names, with file scope, defined in standard headers, are reserved at file scope (in the same namespace) if the corresponding header is #included. (The Standard really says ``each identifier with file scope,'' but the only standard identifiers not covered by rule 4 are typedef and tag names.)
Rules 3 and 4 are additionally complicated by the fact that several sets of macro names and standard library identifiers are reserved for ``future directions'' that is, later revisions of the Standard may define new names matching certain patterns.
Here is a list of the patterns which are reserved for ``future directions'' associared with each standard header:
[TABLE GOES HERE]
(The notation [A-Z] means ``any uppercase letter''; similarly, [a-z] and [0-9] indicate lower-case letters and digits. The notation * means ``anything.'' For example, the pattern for says that all external identifiers beginning with the letters str followed by a lower-case letter are reserved.)
What do the above rules really mean? If you want to be on the safe side:
* 1,2. Don't give anything a name with a leading underscore.
* 3. Don't give anything a name which is already a standard macro (including the ``future directions'' patterns)
. * 4. Don't give any functions or global variables names which are already taken by functions or variables in the standard library, or which match any of the ``future directions'' patterns. (Strictly speaking, ``matching'' means matching in the first six characters, without regard to case;
* 5. Don't redefine standard typedef or tag names.

In fact, the preceding subparagraphs are overly conservative. If you wish, you may remember the following exceptions:
* 1,2. You may use identifiers consisting of an underscore followed by a digit or lower case letter for labels and structure/union members.
* 1,2. You may use identifiers consisting of an underscore followed by a digit or lower case letter at function, block, or prototype scope.
* 3. You may use names matching standard macro names if you don't #include any header files which #define them.
* 4. You may use names of standard library routines as static or local variables (strictly speaking, as identifiers with internal or no linkage).
* 5. You may use standard typedef and tag names if you don't #include any header files which declare them.

However, before making use of any of these exceptions, recognize that some of them are pretty risky (especially exceptions 3 and 5, since you could accidentally #include the relevant header file at a later time, perhaps through a chain of nested #include files), and others (especially the ones labeled 1,2) represent sort of a ``no man's land'' between the user namespaces and the namespaces reserved to the implementation.

One reason for providing these exceptions is to allow the implementors of various add-in libraries a way to declare their own internal or ``hidden'' identifiers. If you make use of any of the exceptions, you won't clash with any identifiers defined by the Standard, but you might clash with something defined by a third-party library you're using. (If, on the other hand, you're the one who's implementing an add-on library, you're welcome to make use of them, if necessary, and if you're careful.)

(It is generally safe to make use of exception 4 to give function parameters or local variables names matching standard library routines or ``future directions'' patterns. For example, ``string'' is a common--and legal--name for a parameter or local variable.)

(Continued on next question...)

Other Interview Questions