...
The C programming language has several mechanisms for creating named, symbolic constants: const
-qualified objects, enumeration constants, and object-like macro definitions. Each of these mechanisms has associated advantages and disadvantages.
...
Code Block |
---|
enum { max = 15 }; int a[max]; /* OK outside function */ const int *p; p = &max; /* Error: '"&'" on enum constant */ |
Enumeration constants do not allow the type of the value to be specified. An enumeration constant whose value can be represented as an int
is always an int
.
...
#
define
identifier replacement-list
defines an object-like macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.
...
The following table summarizes some of the differences between const
-qualified objects, enumeration constants, and object-like macro definitions.
Method | Evaluated At | Consumes Memory | Viewable by Debuggers | Type Checking | Compile-Time Constant Expression |
---|---|---|---|---|---|
Enumerations | Compile time | No | Yes | Yes | Yes |
| Runtime | Yes | Yes | Yes | No |
Macros | Preprocessor | No | No | No | Yes |
Noncompliant Code Example
...
In this compliant solution, the host name and port number are both defined as object-like macros, so they can be passed as compile-time arguments:
Code Block | ||||
---|---|---|---|---|
| ||||
#ifndef PORTNUMBER /* Might be passed on compile line */ # define PORTNUMBER 1234 #endif #ifndef HOSTNAME /* Might be passed on compile line */ # define HOSTNAME "localhost" #endif /* ... */ LDAP *ld = ldap_init(HOSTNAME, PORTNUMBER); if (ld == NULL) { perror("ldap_init"); return(1); } |
Exceptions
DCL06-C-EX1: Although replacing numeric constants with a symbolic constant is often a good practice, it can be taken too far. Remember that the goal is to improve readability. Exceptions can be made for constants that are themselves the abstraction you want to represent, as in this compliant solution.
...
Code Block |
---|
enum { TWO = 2 }; /* aA scalar */ enum { FOUR = 4 }; /* aA scalar */ enum { SQUARE = 2 }; /* anAn exponent */ x = (-b + sqrt(pow(b, SQUARE) - FOUR*a*c))/ (TWO * a); |
...
Using numeric literals makes code more difficult to read and understand. Buffer overruns are frequently a consequence of a magic number being changed in one place (such as in an array declaration) but not elsewhere (such as in a loop through an array).
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL06-C |
Low |
Unlikely |
Medium | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Axivion Bauhaus Suite |
| CertC-DCL06 | |||||||
Compass/ROSE |
Could detect violations of this recommendation merely by searching for the use of "magic numbers" and magic strings in the code itself. That is, any number (except a few canonical numbers: −1, 0, 1, 2) that appears in the code anywhere besides where assigned to a variable is a magic number and should instead be assigned to a | |||||||||
| CC2.DCL06 | Fully implemented | |||||||
Helix QAC |
| C3120, C3121, C3122, C3123, C3131, C3132 | |||||||
LDRA tool suite |
| 201 S | Fully implemented |
Parasoft C/C++test |
|
|
|
3120
3121
3122
3123
3131
3132
CERT_C-DCL06-a | Use meaningful symbolic constants to represent literal values | ||||||||
Polyspace Bug Finder |
| Checks for:
Rec. fully covered. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ |
Coding Standard | VOID DCL06-CPP. Use meaningful symbolic constants to represent literal values in program logic |
MITRE CWE | CWE-547, Use of hard-coded, security-relevant constants |
Bibliography
[Henricson 1992] | Chapter 10, "Constants" |
[Saks 2001a] |
[Saks 2001b] |
[Saks 2002] |
[Summit 2005] | Question 10.5b |
...
...