The C language provides several different kinds of constants: integer constants such as 10
and 0x1C
, floating constants such as 1.0
and 6.022e+23
, and character constants such as 'a'
and '\x10'
. C also provides string literals such as "hello, world"
and "\n"
. These may all be referred to as literals.
Wiki Markup |
---|
Use symbolsmeaningful symbolic constants, rather than raw values, to represent arbitrary constant values. A well-named symbol adds clarity to the program's source code by conveying the meaning of a constant. Using symbolic constants also simplifies maintenance and promotes portability by providing a single change point. Although some constants represent values that never change, many constants represent arbitrary implementation decisions, such as buffer sizes, that are subject to change. If you use a symbol to represent a constant value, you can change the value throughout the program by changing the symbol definition (the single change point) and rebuilding the program \[[Saks 02|AA. C References#Saks 02]\]. |
...
The C programming language has several mechanisms for defining symbolic constants: const
-qualified objects, enumeration constants, and object-like macro definitions.
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), (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
Enumeration Constants
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.
Object-like Macros
A preprocessing directive of the form:
...
Wiki Markup |
---|
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-1999|AA. C References#ISO/IEC 9899-1999]\]. |
#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
...
Code Block | ||
---|---|---|
| ||
char buffer[256]; /* ... */ fgets(buffer, sizeof(buffer), stdin); |
Wiki Markup |
---|
Using the {{sizeof}} expression reduces the total number of names declared in the program, which is almost always a |
good idea \[[Saks 02|AA. C References#Saks 02]\]. |
Compliant Solution
Constant values that may be passed as compile-time arguments must be macro definitions, as shown by this example:
Code Block | ||
---|---|---|
| ||
#ifndef MYPORTNUMBER /* might be passed on compile line */
# define MYPORTNUMBER 1234
#endif
|
Exceptions
DCL06-EX1: While 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.
...