CertC-DCL02

Use visually distinct identifiers

Required inputs: IR

Use visually distinct identifiers with meaningful names to eliminate errors resulting from misreading the spelling of an identifier during the development and review of code. An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter.

Depending on the fonts used, certain characters appear visually similar or even identical:

Character Similar Characters
0 (zero) O (capital o), Q (capital q), D (capital d)
1 (one) I (capital i), l (lowercase L)
2 (two) Z (capital z)
5 (five) S (capital s)
8 (eight) B (capital b)
n (lowercase N) h (lowercase H)
m (lowercase M) rn (lowercase R, lowercase N)

Do not define multiple identifiers that vary only with respect to one or more visually similar characters.

Make the initial portions of long identifiers unique for easier recognition and to help prevent errors resulting from nonunique identifiers. (See DCL23-C. Guarantee that mutually visible identifiers are unique.)

In addition, the larger the scope of an identifier, the more descriptive its name should be. It may be perfectly appropriate to name a loop control variable i, but the same name would likely be confusing if it named a file scope object or a variable local to a function more than a few lines long. See also DCL01-C. Do not reuse variable names in subscopes and DCL19-C. Use as minimal a scope as possible for all variables and functions.

Noncompliant Code Example (Source Character Set)

DCL02-C implicitly assumes global scope, which can be confused with scope within the same file. Although it may not generate any errors, a possible violation of the rule may occur, as in the following example. Note this example does not violate DCL23-C. Guarantee that mutually visible identifiers are unique.

In file foo.h:

int id_O; /* (Capital letter O) */

In file bar.h:

int id_0; /* (Numeric digit zero) */

If a file foobar.c includes both foo.h and bar.h, then both id_0 and id_0 come in the same scope, violating this rule.

Compliant Solution (Source Character Set)

In a compliant solution, use of visually similar identifiers should be avoided in the same project scope.

In file foo.h:

int id_a;

In file bar.h:

int id_b;
Risk Assessment

Failing to use visually distinct identifiers can result in referencing the wrong object or function, causing unintended program behavior.

Recommendation Severity Likelihood Remediation Cost Priority Level
DCL02-C Low Unlikely Medium P2 L3
Related Guidelines
SEI CERT C++ Coding Standard VOID DCL02-CPP. Use visually distinct identifiers
ISO/IEC TR 24772:2013 Choice of Clear Names [NAI]
MISRA C:2012 Directive 4.5 (advisory)
Excerpt from SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition) and SEI CERT C Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/recommendations/declarations-and-initialization-dcl/dcl02-c], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

ambiguous

Identifiers are typographically ambiguous

None

False

casing

Identifiers only differ in casing

None

False

Options

allow_member_initializers

allow_member_initializers : bool = False

Allows ambiguous names for constructor parameters that are used to initialize members.
 

check_case

check_case : bool = False

If true, also check for case differences in identifiers.
 

distinguish_c_name_spaces

distinguish_c_name_spaces : bool = True

Whether to allow similar identifiers in different C name spaces (type tag/label/member/ordinary identifier).
 

distinguish_macro_names

distinguish_macro_names : bool = False

Whether to allow macros to same similar names as other identifiers.
 

distinguish_type_names

distinguish_type_names : bool = False

Whether to allow types to have similar names as other identifiers. For example, a variable declaration MyClass myClass; is allowed by this option.

Note: unlike the option distinguish_c_name_spaces, this option also distinguishes typedef names, not just struct/class tag names.

 

exclude_system_headers

exclude_system_headers : bool = False

Whether to exclude identifiers appearing in system headers.
 

normalizations

normalizations

Type: list[typing.Tuple[str, str]]

Default: [('Q', 'O'), ('D', 'O'), ('0', 'O'), ('1', 'l'), ('I', 'l'), ('5', 'S'), ('2', 'Z'), ('8', 'B'), ('h', 'n'), ('rn', 'm'), ('1', 'I'), ('0', 'Q'), ('0', 'D'), ('D', 'Q')]

Which pairs of characters should be seen as ambiguous.
 

pre_excludes

pre_excludes : set[bauhaus.analysis.config.FileGlobPattern] = set()

Exclude identifiers appearing in files matching a path globbing pattern.
 

treat_global_excludes_as_pre_excludes

treat_global_excludes_as_pre_excludes : bool = False

Explicitly treat global excludes like pre_excludes if this option is set to true.