Extended macro example
Here are some examples of macros taken from actual working C code, in this case the code of GNU Emacs, the text editor of choice for many C programmers, and in fact the editor in which this edition of the book was written.
Most of the macro examples below define various types of integer as having certain sizes. It can be very useful when doing advanced C programming to know whether a long integer, for instance, is 32 or 64 bits long on your system; if you select the wrong size, your code might crash or might not even compile. In the case of Emacs, the maximum size of certain variables (how many bits they contain) affects every aspect of its operation, even determining how long an Emacs text file can be.
Each piece of code below is prefixed with the name of the file from which the code is taken, and followed by a note on some interesting features of the macros defined.
/* Note that lisp.h uses this in a preprocessor conditional, so it would not work to use sizeof. That being so, we do all of them without sizeof, for uniformity's sake. */ #ifndef BITS_PER_INT #define BITS_PER_INT 32 #endif #ifndef BITS_PER_LONG #ifdef _LP64 #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif #endif
In the middle of this set of macros, from
config.h, the Emacs programmer used the characters
*/to create an ordinary C comment. C comments can be interspersed with macros freely.
BITS_PER_INTis defined here to be 32 (but only if it is not already defined, thanks to the
#ifndefdirective). The Emacs code will then treat integers as having 32 bits. (See Integer variables.)
The second chunk of macro code in this example checks to see whether
BITS_PER_LONGis defined. If it is not, but
_LP64is defined, it defines
BITS_PER_LONGto be 64, so that all long integers will be treated as having 64 bits. (
_LP64is a GCC macro that is defined on 64-bit systems. It stands for "longs and pointers are 64 bits".) If
_LP64is not present, the code assumes it is on a 32-bit system and defines
BITS_PER_LONGto be 32.
/* These are default choices for the types to use. */ #ifdef _LP64 #ifndef EMACS_INT #define EMACS_INT long #define BITS_PER_EMACS_INT BITS_PER_LONG #endif #ifndef EMACS_UINT #define EMACS_UINT unsigned long #endif #else /* not _LP64 */ #ifndef EMACS_INT #define EMACS_INT int #define BITS_PER_EMACS_INT BITS_PER_INT #endif #ifndef EMACS_UINT #define EMACS_UINT unsigned int #endif #endif
This set of macros, from
lisp.h, again checks to see whether
_LP64is defined. If it is, it defines
long(if it is not already defined), and
BITS_PER_EMACS_INTto be the same as
BITS_PER_LONG, which was defined in
config.h, above. It then defines
EMACS_UINTto be an
unsigned long, if it is not already defined.
_LP64is not defined, it is assumed we are on a 32-bit system.
EMACS_INTis defined to be an
intif it is not already defined, and
EMACS_UINTis defined to be an
unsigned intif it is not already defined.
Again, note that the programmer has freely interspersed a comment with the preprocessor code.
/* These values are overridden by the m- file on some machines. */ #ifndef VALBITS #define VALBITS (BITS_PER_EMACS_INT - 4) #endif
Here is another example from
lisp.h. The macro
VALBITS, which defines another size of integer internal to Emacs, is defined as four less than
BITS_PER_EMACS_INT-- that is, 60 on 64-bit systems, and 28 on 32-bit systems.
#ifndef XINT /* Some machines need to do this differently. */ #define XINT(a) ((EMACS_INT) (((a) << (BITS_PER_EMACS_INT - VALBITS)) \ >> (BITS_PER_EMACS_INT - VALBITS))) #endif
The interesting feature of the
XINTmacro above is not only that it is a function, but that it is broken across multiple lines with the backslash character (
\). The GCC preprocessor simply deletes the backslash, deletes the preceding whitespace from the next line, and appends it where the backslash was. In this way, it is possible to treat long, multi-line macros as though they are actually on a single line. (See Advanced operators, for more information on the the advanced operators