18. The C Preprocessor

Furthermore, lam of the opinion that Cpp must he destroyed.

Cato the Elder (Marcus Porcius Cato)

Problems with the C preprocessor, Cpp — alternatives to Cpp constructs — banning Cpp.

18.1 Cpp

Among the facilities, techniques, and ideas C++ inherited from C was the C preprocessor, Cpp. I didn’t like Cpp at all, and I still don’t like it. The character and file orientation of the preprocessor is fundamentally at odds with a programming language designed around the notions of scopes, types, and interfaces. For example, consider this innocent-looking code fragment:

#include<stdio.h>
extern double sqrt(double);

main()
{
    printf("The square root of 2 is %g ",sqrt(2));
    fflush(stdout);
    return(0);
}

What does it do? Print

The square root of 2 is 1.41421

maybe? That seems plausible, but actually I compiled it with

cc -Dsqrt=rand -Dreturn=abort

so it printed

The square root of 2 is 7.82997e+28
abort – core dumped

and left a core image behind.

This example may be extreme, and you might consider the use of compiler options to define Cpp macros not quite sportsmanlike, but the example is not unrealistic. Macro definitions can lurk in environments, compiler directives, and header files. Macro substitution cuts across all scope barriers, can indeed change the scope structure of a program by inserting braces, quotes, etc., and allows a programmer to change what the compiler proper sees without even touching the source code. Occasionally, even the most extreme uses of Cpp are useful, but its facilities are so unstructured and intrusive that they are a constant problem to programmers, maintainers, people porting code, and tool builders.

In retrospect, maybe the worst aspect of Cpp is that it has stifled the development of programming environments for C. The anarchic and character-level operation of Cpp makes nontrivial tools for C and C++ larger, slower, less elegant, and less effective than one would have thought possible.

Cpp isn’t even a very good macroprocessor. Consequently, I set out to make Cpp redundant. That task turned out to be far harder than expected. Cpp may be ugly, but it is hard to find better-structured and efficient alternatives for all of its varied uses.

The C preprocessor has four fundamental directives:

[1] #include to copy source text from another file.

[2] #define to define a macro (with or without arguments).

[3] #ifdef to include lines of code dependent on a condition.

[4] #pragma to affect the compilation in an implementation-dependent manner.

These directives are used to express a variety of basic programming tasks:

#include

– Make interface definitions available.

– Compose source text.

#define

– Define symbolic constants.

– Define open subroutines.

– Define generic subroutines.

– Define generic “types.”

– Renaming.

– String concatenation.

– Define special purpose syntax.

– General macro processing.

#ifdef

– Version control.

– Commenting out code.

#pragma

– Control of layout.

– Informing the compiler about unusual control flow.

Cpp does all of these tasks pretty badly, mostly by indirect means, but cheaply and often adequately. Most important, Cpp is available everywhere C is, and it is well known. This has often made it more useful than far better, but less widely available and less widely known, macroprocessors. This aspect is so important that the C preprocessor is frequently used for tasks that have very little to do with the C language, but that is not a C++ problem.

C++ provides alternatives for the main uses of #define:

const for constants (§3.8).

inline for open subroutines (§2.4.1).

template for functions parameterized by types (§15.6).

template for parameterized types (§15.3).

namespace for more general naming (§ 17).

C++ provides no alternative for #include, though namespaces provide a scope mechanism that supports composition in a way that can be used to make #include better behaved.

I have suggested that an include directive might be added to C++ proper as an alternative to Cpp’s #include. A C++ include directive would differ from Cpp’s #include in three ways:

[1] If a file is included twice, the second include is ignored. This solves a practical problem that is currently solved inefficiently and awkwardly by #defines and #ifdefs.

[2] Macros defined outside included text don’t get expanded within the included text. This provides a mechanism for insulating information from interference from macros.

[3] Macros defined inside included text don’t get expanded in text processed after the included text. This ensures that macros in included text don’t impose order dependencies on the including compilation unit and generally protects against surprises caused by macros.

This mechanism would be a boon to systems that precompile header files and, in general, for people who compose software out of independent parts. Please note, however, that this is only an idea, not an accepted language feature.

This leaves #ifdef and #pragma. I could live without #pragma because I have never seen a pragma that I liked. Too often, #pragma seems to be used to sneak variations of language semantics into a compiler and to provide extensions with very specialized semantics and awkward syntax. We don’t yet have a good alternative for #ifdef. In particular, using if-statements and constant expressions is not a complete alternative. For example:

const C = 1;

// . . .

if (C) {
    // . . .
}

This technique cannot be used to control declarations and the text of an if-statement must be syntactically correct and type check even if it is part of a branch that an execution will never take.

I’d like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and then – years later – banish Cpp into the program development environment with the other extra-linguistic tools where it belongs.

The #if, #line, and #undef directives can be important, but they do not impinge on this discussion.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset