Tools: HeaderDoc User's Guide: Using the C Preprocessor

## Using the C Preprocessor

Beginning in HeaderDoc 8.5, HeaderDoc contains a basic C preprocessor implementation (enabled with the `-p` flag). Because HeaderDoc does not have access to the full compile-time environment of the headers, its behavior may differ from normal C preprocessors in certain cases. This section describes some of those differences.

#### In this section:

> Parsing Rules
> Multiply-Defined Macros
> Embedded HeaderDoc Comments in a Macro
> Handling of #include
> Other Issues
> What if I Don’t Want to See the Macros in the Documentation?

### Parsing Rules

Most `#define` macros are not parsed by default, even if the preprocessor is enabled. This permits you as the user to choose which macros to process.

Macros are processed if any of the following are true:

- They are preceded by a HeaderDoc comment block.

- They appear between the beginning and end of a class that is preceded by a HeaderDoc comment block.

The reason for this second case is a side-effect of the way that HeaderDoc parses classes to ensure that lines are processed in the order in which they appear in the file (which is necessary for a preprocessor to even be possible). For maximum control, preprocessor directives should be at the start of the file, outside of class braces.

### Multiply-Defined Macros

HeaderDoc does not attempt to handle `#if`, `#ifdef`, or `#ifndef` directives. This may, in certain circumstances, result in multiple definitions of a `#define` directive if the preprocessor is enabled. As with most preprocessors, all such definitions are ignored except for the one that appears first in the file.

This is made slightly more complicated by the parsing rules described in “Parsing Rules”.

### Embedded HeaderDoc Comments in a Macro

With most data types, HeaderDoc comments appearing inside the data type are associated with the data type itself. This is normally true for `#define` macros as well. However, that behavior would create a problem when the C preprocessor is enabled, as it is reasonable to allow macros to define contents to be blown into a class, and those contents could potentially include HeaderDoc markup.

For this reason, when the C preprocessor is enabled, embedded headerdoc processing is disabled for `#define` macros marked with `@parseonly`. Any HeaderDoc markup within the body of such a macro will be blown in wherever the macro is used, and will only be processed in the resulting context.

While HeaderDoc does allow a macro to insert multiple declarations and HeaderDoc comment blocks within a class, it does not allow this outside of a class. When a macro inserts HeaderDoc comments outside of a class scope, parsing will end at the end of the first declaration and any other contents inserted by the macro will be skipped.

### Handling of #include

HeaderDoc’s implementation of `#include` behaves differently than you might expect. The differences include the following:

- No notion of paths.

  Because the include paths are not specified as they are with a compiler, HeaderDoc cannot reasonably determine that `<dir1/file.h>` and `<dir2/file.h>` are distinct. For this reason, processing files with the same name in different directories is discouraged.

- Mandatory recursion protection.

  Because HeaderDoc does not process `#if`, `#ifdef`, and `#ifndef` conditionals, HeaderDoc enforces recursion protection by not allowing a file to get processed twice. Once a file is processed, a precompiled copy of its macros is stored for future use, and is automatically inserted whenever another `#include` requests it.

  While most well-behaved headers will be handled correctly, this has two potential side-effects in a few cases. They are as follows:

  - A `#include` cannot be altered in a context-dependent way—that is, if a header incudes `<a.h>` and then `<b.h>`, the macros defined in `<a.h>` will not automatically affect the parse of `<b.h>`. In the rare cases where this matters, it can be fixed by making sure that `<b.h>` includes `<a.h>`.

  - The `#include` directive behaves much like `#import`. The result is that if `<a.h>` includes `<b.h>` which includes `<c.h>` which includes `<a.h>`, the definitions leading up to the reinclusion of `<a.h>` will not affect the way `<a.h>` is parsed. Granted, such use of macros borders on obfuscated C, but in theory, it could cause unexpected behavior....

- Macro contents will be shown in the documentation output.

  Rather than try to carry around some notion of the original tokens read from the file, HeaderDoc inserts macros into the parse tree as if the modified version had been read from the file. This means that it is not possible, for example, for HeaderDoc to show you the unaltered definition of a macro that includes another macro. (The same applies for data types, functions, and so on if they are altered by a macro, though this is generally the expected behavior.)

These differences generally do not affect headers written in a typical fashion, but may cause problems if you are using preprocessor directives in a nonstandard way.

### Other Issues

A few common function-like preprocessor macros are predefined within HeaderDoc itself to avoid parse problems with I/O Kit headers. These will probably not affect you, but you should be aware of them.

Because HeaderDoc does not strip comments prior to processing macros (since doing so would remove HeaderDoc markup), the preprocessor may behave in subtly different ways. In particular, newlines are preserved, and any closing single-line (`//`) comments in macros will automatically be converted into a multi-line (`/* */`) comment to avoid causing the rest of the line to disappear when that macro actually gets used.

Finally, HeaderDoc does do basic string, character, and comment handling, even within macros. As a result, mismatched single or double quotes within a `#define` macro may cause serious problems.

### What if I Don’t Want to See the Macros in the Documentation?

Most of the time, having `#define` macros defined in the documentation is helpful. In some cases, though, the macros get so big and ugly that you just want to get rid of them. For this reason, HeaderDoc has the `@parseOnly` tag.

For example:

    /*! This is an ugly internal macro. @parseOnly */
| `
`
    #define CreateStructors \
| `
`
        /*! Constructor */ \
| `
`
        blah(); \
| `
`
        /*! Destructor */ \
| `
`
        ~blah();
| `
`

By adding this tag at the end of the HeaderDoc comment block for the macro, the macro will be parsed and used by the preprocessor, but will not appear in the documentation.

© 1999, 2004 Apple Computer, Inc. All Rights Reserved. (Last updated: 2004-10-27)