Node:Extended macro example, Next:Questions 12, Previous:Macros, Up:Preprocessor directives
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.
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 definesBITS_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 definesBITS_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 definesEMACS_INT
aslong
(if it is not already defined), andBITS_PER_EMACS_INT
to be the same asBITS_PER_LONG
, which was defined inconfig.h
, above. It then definesEMACS_UINT
to be anunsigned 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 anint
if it is not already defined, andEMACS_UINT
is defined to be anunsigned 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 macroVALBITS
, which defines another size of integer internal to Emacs, is defined as four less thanBITS_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>>
.)