Value substitution
When programming in
C, the preprocessor is liberally
used to create macros and to substitute values.
Because the preprocessor simply
does text replacement and has no concept nor facility for type checking,
preprocessor value substitution introduces subtle problems that can be avoided
in C++ by using const values.
The typical use of the preprocessor to
substitute values for names in C looks like this:
#define BUFSIZE 100
BUFSIZE is a name that only exists
during preprocessing, therefore it doesn’t occupy storage and can be
placed in a header file to provide a single value for all translation units that
use it. It’s very important for code maintenance to use value substitution
instead of so-called “magic numbers.” If you
use magic numbers in your code, not only does the reader have no idea where the
numbers come from or what they represent, but if you decide to change a value,
you must perform hand editing, and you have no trail to follow to ensure you
don’t miss one of your values (or accidentally change one you
shouldn’t).
Most of the time, BUFSIZE will
behave like an ordinary variable, but not all the time. In addition,
there’s no type information. This can hide bugs that are very difficult to
find. C++ uses const to eliminate these problems by bringing value
substitution into the domain of the compiler. Now you can say
const int bufsize = 100;
You can use bufsize anyplace where
the compiler must know the value at compile time. The compiler can use
bufsize to perform
constant folding, which means the compiler will
reduce a complicated constant expression to a simple one by performing the
necessary calculations at compile time. This is especially important in array
definitions:
char buf[bufsize];
You can use const for all the
built-in types (char, int, float, and double) and
their variants (as well as class objects, as you’ll see later in this
chapter). Because of subtle bugs that the preprocessor might introduce, you
should always use const instead of #define
value
substitution.