Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

When used in program logic, literals can reduce the readability of source code. As a result, literals, in general, and integer constants, in particular, are frequently called magic numbers because their purpose is often obscured. Magic numbers can be constant values that represent either an arbitrary value (such as a determined appropriate buffer size) or a malleable concept (such as the age at which a person is considered an adult, which can change between geopolitical boundaries). Rather than embed literals in program logic, use appropriately named symbolic constants to clarify the intent of the code. In addition, if a specific value needs to be changed, reassigning a symbolic constant once is more efficient and less error prone than replacing every instance of the value [Saks 2002].

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.

const-

...

Qualified Objects

Objects that are const-qualified have scope and can be type-checked by the compiler. Because these are named objects (unlike macro definitions), some debugging tools can show the name of the object. The object also consumes memory.

A const-qualified object allows you to specify the exact type of the constant. For example,

Code Block

const unsigned int buffer_size = 256;

...

const-qualified objects allow the programmer to take the address of the object.

Code Block

const int max = 15;
int a[max]; /* invalid declaration outside of a function */
const int *p;

/* a const-qualified object can have its address taken */
p = &max;

...

Enumeration constants can be used to represent an integer constant expression that has a value representable as an int. Unlike const-qualified objects, enumeration constants do not consume memory. No storage is allocated for the value, so it is not possible to take the address of an enumeration constant.

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.

Object-

...

like Macros

A preprocessing directive of the form

...

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 [ISO/IEC 9899:19992011].

C programmers frequently define symbolic constants as object-like macros. For example, the code

Code Block

#define buffer_size 256

defines buffer_size as a macro whose value is 256. The preprocessor substitutes macros before the compiler does any other symbol processing. Later compilation phases never see macro symbols, such as buffer_size; they see only the source text after macro substitution. As a result, many compilers do not preserve macro names among the symbols they pass on to their debuggers.

...

The following table summarizes some of the differences between const-qualified objects, enumeration constants, and object-like macro definitions.

Method

Evaluated at At

Consumes Memory

Viewable by Debuggers

Type Checking

Compile-time constant expression Time Constant Expression

enumerations Enumerations

compile time

no

yes

yes

yes

const-qualified

run time runtime

yes

yes

yes

no

Macros macros

preprocessor

no

no

no

yes

Noncompliant Code Example

...

Code Block
bgColor#ffcccc
langc

/* ... */
if (age >= 18) {
   /* Take action */
}
else {
  /* Take a different action */
}
/* ... */

...

Code Block
bgColor#ccccff
langc

enum { ADULT_AGE=18 };
/* ... */
if (age >= ADULT_AGE) {
   /* Take action */
}
else {
  /* Take a different action */
}
/* ... */

...

Code Block
bgColor#ffcccc
langc

char buffer[256];
/* ... */
fgets(buffer, 256, stdin);

This use of integer literals can easily result in buffer overflows, if, for example, the buffer size is reduced but the integer literal used in the call to fgets() is not.

Compliant Solution (enum)

In this compliant solution, the integer literal is replaced with an enumeration constant. (See recommendation DCL00-C. Const-qualify immutable objects.)

Code Block
bgColor#ccccff
langc

enum { BUFFER_SIZE=256 };

char buffer[BUFFER_SIZE];
/* ... */
fgets(buffer, BUFFER_SIZE, stdin);

...

Frequently, it is possible to obtain the desired readability by using a symbolic expression composed of existing symbols rather than by defining a new symbol. For example, a sizeof expression can work just as well as an enumeration constant. (See recommendation EXP09-C. Use sizeof to determine the size of a type or variable.)

Code Block
bgColor#ccccff
langc

char buffer[256];
/* ... */
fgets(buffer, sizeof(buffer), stdin);

...

Code Block
bgColor#ffcccc
langc

LDAP *ld = ldap_init("localhost", 1234);
if (ld == NULL) {
  perror("ldap_init");
  return(1);
}

...

In this compliant solution, the host name and port number are both defined as object-like macros, so that so they can be passed as compile-time arguments.

Code Block
bgColor#ccccff
langc

#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-EX1: While  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
bgColor#ccccff
langc

x = (-b + sqrt(b*b - 4*a*c)) / (2*a);

Replacing numeric constants with symbolic constants in this example does nothing to improve the readability of the code and can actually make the code more difficult to read.

Code Block

enum { TWO = 2 };     /* a scalar */
enum { FOUR = 4 };    /* a scalar */
enum { SQUARE = 2 };  /* an exponent */
x = (-b + sqrt(pow(b, SQUARE) - FOUR*a*c))/ (TWO * a);

...

Note that this example does not check for invalid operations (taking the sqrt() of a negative number). See rule FLP32-C. Prevent or detect domain and range errors in math functions for more information on detecting domain and range errors in math functions.

...

LDRA tool suite

201 S

section

Fully

Implemented

implemented

Tool

Version

Checker

Description

Section
Include Page
LDRA_V
LDRA_V
Section

Fully

Implemented section

implemented

Compass/ROSE

 

 

section

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 (

besides

except a few canonical numbers:

-1

−1, 0, 1, 2) that appears in the code

anywhere besides being assigned

anywhere besides where assigned to a variable is a magic number

,

and should instead be assigned to a const integer, enum, or macro. Likewise, any string literal (except "" and individual characters) that appears in the code anywhere

besides being

besides where assigned to a char* or char[] is a magic string.


section

ECLAIR

Include Page
ECLAIR_V
ECLAIR_V
section

nomagicc

Section

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

...

CERT C++ Secure Coding Standard: DCL06-CPP. Use meaningful symbolic constants to represent literal values in program logic

ISO/IEC 9899:19992011 Section 6.3.2.1, "Lvalues, arrays, and function designators," Section 6.7, "Declarations," Section 6.7.2.2, "Enumeration specifiers," and Section 6.10.3, "Macro replacement"

...

MITRE CWE: CWE-547, "Use of Hardhard-coded, Securitysecurity-relevant Constantsconstants"

Bibliography

[Henricson 1992] Chapter 10, "Constants"
[Saks 2001a]
[Saks 2001b]
[Saks 2002]
[Summit 2005] Question 10.5b

...