Names may be constrained by the scope of the name (external, file static, internal), the file in which the identifier is defined, the type of the identifier, and global constraints.
Of course, this is a complete jumble to the uninitiated, and that's the joke.
- Charles Simonyi, on the Hungarian naming convention
Czech names denote operations and variables of abstract types by preceding the names by <type>_. The remainder of the name should begin with a lowercase character, but may use any other character besides the underscore. Types may be named using any non-underscore characters.
The Czech naming convention is selected by the czech flag. If accessczech is on, a function, variable, constant or iterator named <type>_<name> has access to the abstract type <type>.
Reporting of violations of the Czech naming convention is controlled by different flags depending on what is being declared:
Functions and iterators. An error is reported for a function name of the form <prefix>_<name> where <prefix> is not the name of an accessible type. Note that if accessczech is on, a type named <prefix> would be accessible in a function beginning with <prefix>_. If accessczech is off, an error is reported instead. An error is reported for a function name that does not have an underscore if any abstract types are accessible where the function is defined.czechvars
Variables, constants and expanded macros. An error is reported if the identifier name starts with <prefix>_ and prefix is not the name of an accessible abstract type, or if an abstract type is accessible and the identifier name does not begin with <type>_ where type is the name of an accessible abstract type. If accessczech is on, the representation of the type is visible in the constant or variable definition.czechtypes
User-defined types. An error is reported if a type name includes an underscore character.
The slovak flag selects the Slovak naming convention. Like Czech names, it may
be used with accessslovak to control access to abstract representations. The
slovakfcns, slovakvars, slovakconstants, and slovakmacros flags are analogous
to the similar Czech flags. If slovaktype is on, an error is reported if a
type name includes an uppercase letter.
9.1.3 Czechoslovak Names
Czechoslovak names are a combination of Czech names and Slovak names.
Operations may be named either <type>_ followed by any
sequence of non-underscore characters, or <type> followed by an
uppercase letter and any sequence of characters. Czechoslovak names have been
out of favor since 1993, but may be necessary for checking legacy code. The
czechoslovakfcns, czechoslovakvars, czechoslovakmacros, and
czechoslovakconstants flags are analogous to the similar Czech flags. If
czechoslovaktype is on, an error is reported if a type name contains either an
uppercase letter or an underscore character.
9.2 Namespace Prefixes
Another way to restrict names is to constrain the leading character sequences
of various kinds of identifiers. For example, a the names of all user-defined
types might begin with "T" followed by an uppercase letter and all file static
names begin with an uppercase letter. This may be useful for enforcing a
namespace (e.g., all names exported by the X-windows library should begin with
"X") or just making programs easier to understand by establishing an enforced
convention. LCLint can be used to constrain identifiers in this way to detect
identifiers inconsistent with prefixes.
All namespace flags are of the form, -<context>prefix <string>. For example, the macro variable namespace restricting identifiers declared in macro bodies to be preceded by "m_" would be selected by -macrovarprefix "m_". The string may contain regular characters that may appear in a C identifier. These must match the initial characters of the identifier name. In addition, special characters (shown in Table 1) can be used to denoted a class of characters. The * character may be used at the end of a prefix string to specify the rest of the identifier is zero or more characters matching the character immediately before the *. For example, the prefix string "T&*" matches "T" or "TWINDOW" but not "Twin".
^ Any uppercase letter, A-Z & Any lowercase letter, a-z % Any character that is not an uppercase letter (allows lowercase letters, digits and underscore) ~ Any character that is not a lowercase letter (allows uppercase letters, digits and underscore) $ Any letter (a-z, A-Z) / Any letter or digit (A-Z, a-z, 0-9) ? Any character valid in a C identifier # Any digit, 0-9Table 1. Prefix character codes.
Different prefixes can be selected for the following identifier
Any variable declared inside a macro bodyuncheckedmacroprefix
Any macro that is not checked as a function or constant (see Section 8.4)tagprefix
Tags for struct, union and enum declarationsenumprefix
Members of enum typestypeprefix
Name of a user-defined typefilestaticprefix
Any identifier with file static scopeglobvarprefix
Any variable (not of function type) with global variables scopeexternalprefix
Any exported identifier
If an identifier is in more than one of the namespace contexts, the most specific defined namespace prefix is used (e.g., a global variable is also an exported identifier, so if globalvarprefix is set, it is checked against the variable name; if not, the identifier is checked against the externalprefix.)
For each prefix flag, a corresponding flag named <prefixname>exclude controls whether errors are reported if identifiers in a different namespace match the namespace prefix. For example, if macrovarprefixexclude is on, LCLint checks that no identifier that is not a variable declared inside a macro body uses the macro variable prefix.
Here is a (somewhat draconian) sample naming convention:
unchecked macros have no lowercase letters
all type typenames begin with T followed by an uppercase letter. The rest of the name is all lowercase letters.
no identifier that does not name a user-defined type may begin with the type name prefix (set above)
file static scope variables begin with an uppercase letter and three lowercase letters
all global variables variables start with G
no identifier that is not a global variable starts with G
Naming Restrictions Additional naming
restrictions can be used to check that names do no conflict with names
reserved for the standard library, and that identifier are sufficiently
distinct (either for the compiler and linker, or for the programmer.)
Restrictions may be different for names that are needed by the linker
(external names) and names that are only needed during
compilations (internal names). Names of non-static functions and
global variables are external; all other names are internal.
Reserved Names Many names are reserved for the
implementation and standard library. A complete list of reserved names
found in [vdL, p. 126-128] or [ANSI, Section 4]. Some name prefixes such as str
followed by a lowercase character are reserved for future library
extensions. Most C compilers do not detect naming conflicts, and they
can lead to unpredictable program behavior. If ansireserved is on,
LCLint reports errors for external names that conflict with reserved
names. If ansireservedinternal is on, errors are also reported for
9.3.2 Distinct Identifiers
The decision to retain the old six-character case-insensitive restriction on significance was most painful.
- ANSI C Rationale
LCLint can check that identifiers differ within a given number of characters, optionally ignoring alphabetic case and differences between characters that look similar. The number of significant characters may be different for external and internal names.
Using +distinctexternalnames sets the number of significant characters for external names to six and makes alphabetical case insignificant for external names. This is the minimum significance acceptable in an ANSI-conforming compiler. Most modern compilers exceed these minimums (which are particularly hard to follow if one uses the Czech or Slovak naming convention). The number of significant characters can be changed using the externalnamelength <number> flag. If externalnamecaseinsensitive is on, alphabetical case is ignored in comparing external names. LCLint reports identifiers that differ only in alphabetic case.
For internal identifiers, a conforming compiler must recognize at least 31 characters and treat alphabetical cases distinctly. Nevertheless, it may still be useful to check that internal names are more distinct then required by the compiler to minimize the likelihood that identifiers are confused in the program. Analogously to external names, the internalnamelength <number> flag sets the number of significant characters in an internal name and internalnamecaseinsensitive sets the case sensitivity. The internalnamelookalike flag further restricts distinctions between identifiers. When set, similar-looking characters match -- the lowercase letter "l" matches the uppercase letter "I" and the number "1"; the letter "O" or "o" matches the number "0"; "5" matches "S"; and "2" matches "Z". Identifiers that are not distinct except for look-alike characters will produce an error message. External names are also internal names, so they must satisfy both the external and internal distinct identifier checks.
Figure 18 illustrates some of the name checking done by LCLint.