Node:Extended macro example, Next:Questions 12, Previous:Macros, Up:Preprocessor directives
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.
emacs/src/config.h
/* 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 /*
and */
to create an
ordinary C comment. C comments can be interspersed with macros freely.
The macro BITS_PER_INT
is defined here to be 32 (but only if it
is not already defined, thanks to the #ifndef
directive). 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_LONG
is defined. If it is not, but _LP64
is
defined, it defines BITS_PER_LONG
to be 64, so that all long
integers will be treated as having 64 bits. (_LP64
is a GCC
macro that is defined on 64-bit systems. It stands for "longs and
pointers are 64 bits".) If _LP64
is not present, the
code assumes it is on a 32-bit system and defines BITS_PER_LONG
to be 32.
emacs/src/lisp.h
/* 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 _LP64
is defined. If it is, it defines EMACS_INT
as long
(if it is not already defined), and
BITS_PER_EMACS_INT
to be the same as BITS_PER_LONG
, which
was defined in config.h
, above. It then defines
EMACS_UINT
to be an unsigned long
, if it is not already
defined.
If _LP64
is not defined, it is assumed we are on a 32-bit
system. EMACS_INT
is defined to be an int
if it is not
already defined, and EMACS_UINT
is defined to be an
unsigned int
if it is not already defined.
Again, note that the programmer has freely interspersed a comment with the preprocessor code.
emacs/src/lisp.h
/* 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.
emacs/src/lisp.h
#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 XINT
macro 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 <<
and >>
.)