const
Instead of #define
to Define ConstantsSymbolic constants make code more readable and maintainable. The constant’s name indicates its meaning, and if you need to change the value, you just have to change the value once, in the definition, and then recompile. C uses the preprocessor to create symbolic names for a constant:
#define MAX_LENGTH 100
The preprocessor then does a text substitution in your source code, replacing occurrences of MAX_LENGTH
with 100
prior to compilation.
The C++ approach is to apply the const
modifier to a variable declaration:
const int MAX_LENGTH = 100;
This treats MAX_LENGTH
as a read-only int
.
There are several advantages to using the const
approach. First, the declaration explicitly names the type. With #define
, you must use various suffixes to a number to indicate types other than char
, int
, or double
; for example, you use 100L
to indicate a long
type and 3.14F
to indicate a float
type. More importantly, the const
approach can just as easily be used with compound types, as in this example:
const int base_vals[5] = {1000, 2000, 3500, 6000, 10000};
const string ans[3] = {"yes", "no", "maybe"};
Finally, const
identifiers obey the same scope rules as variables. Thus, you can create constants with global scope, named namespace scope, and block scope. If, say, you define a constant in a particular function, you don’t have to worry about the definition conflicting with a global constant used elsewhere in a program. For example, consider the following:
#define n 5
const int dz = 12;
...
void fizzle()
{
int n;
int dz;
...
}
The preprocessor will replace
int n;
with
int 5;
and induce a compilation error. The dz
defined in fizzle()
, however, will be a local variable. Also if necessary, fizzle()
can use the scope-resolution operator (::
) and access the constant as ::dz
.
C++ has borrowed the const
keyword from C, but the C++ version is more useful. For example, the C++ version has internal linkage for external const
values rather than the default external linkage used by variables and by the C const
. This means that each file in a program using a const
needs that const
defined in that particular file. This might sound like extra work, but, in fact, it makes life easier. With internal linkage, you can place const
definitions in a header file used by various files in a project. That is a compiler error for external linkage but not for internal linkage. Also because a const
must be defined in the file that uses it (being in a header file used by that file satisfies the requirement), you can use const
values as array size arguments:
const int MAX_LENGTH = 100;
...
double loads[MAX_LENGTH];
for (int i = 0; i < MAX_LENGTH; i++)
loads[i] = 50;
This won’t work in C because the defining declaration for MAX_LENGTH
could be in a separate file and not be available when this particular file is compiled. In fairness, it should be added that, in C, you could use the static
modifier to create constants with internal linkage. It’s just that C++, by making static
the default, requires one fewer thing for you to remember.
Incidentally, the revised C Standard (C99) allows you to use a const
as an array size specification, but the array is treated as a new form of array, called a variable array, that is not part of the C++ Standard.
One role for the #define
directive is still quite useful—the standard idiom for controlling when a header file is compiled:
// blooper.h
#ifndef _BLOOPER_H_
#define _BLOOPER_H_
// code goes here
#endif
For typical symbolic constants, however, you should get into the habit of using const
instead of #define
. Another good alternative, particularly when you have a set of related integer constants, is to use enum
:
enum {LEVEL1 = 1, LEVEL2 = 2, LEVEL3 = 4, LEVEL4 = 8};
18.119.162.49