Avoid the use of magic numbers in code when possible. Magic numbers are constant values that represent either an arbitrary value (such as a determined appropriate buffer size) or a malleable concept (such as the age a person is considered an adult, which could change between geopolitical boundaries). Rather, 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.
The C programming language has several mechanisms for defining symbolic constants: const
-qualified objects, enumeration constants, and macro definitions.
Objects that are const
-qualified have scope and can be type-checked by the compiler. Because these are named objects (unlike macro definitions), (certain) debugging tools can show the name of the object. The objects also consumes memory (though this is not too important). Unfortunately, const
-qualified objects cannot be used where compile-time integer constants are required, namely to define the
- size of a bit-field member of a structure
- size of an array (except in the case of variable length arrays)
- value of an enumeration constant
- value of a
case
constant
An enumeration constant is a member of an enumeration. Enumeration constant 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 require that storage is allocated for the value so it is not possible to take the address of an enumeration constant.
#define:
- operates at compile time
- consumes no memory (though this is not too important)
- can use in compile-time constant expression
- uses different syntax; can make mistake with ;
- can't create pointers to
- no type checking
const:
- operates at run time
- consumes memory (though this is not too important)
- can't use in compile-time constant expression
- uses consistent syntax
- can create pointers to
- does type checking
If any of these are required, then an integer constant (which would be an rvalue) must be used.
Method | Evaluated at | Consumes Memory | Viewable by Debuggers | Type Checking | Compile-time constant expression |
---|---|---|---|---|---|
Enumerations | compile time | no | yes | yes | no |
| run time | yes | yes | yes | no |
Macros | preprocessor | no | no | no | yes |
Non-Compliant Code Example
...