ugh.book

(singke) #1

212 C++


C weenies will tell you that one of the best features of C is the pre-
processor. Actually, it is probably the worst. Many C programs are
unintelligible rats’ nests of #ifdefs. (Almost none of which would be
there if the various versions of Unix were actually compatible.) But
that’s only the beginning.

The worst problem with the C preprocessor is that it locks the Unix
world into the text-file prison and throws away the key. It is virtually
impossible to usefully store C source code in any form other than lin-
ear text files. Why? Because it is all but impossible to parse unpre-
processed C code. Consider, for instance:

#ifdef BSD
int foo() {
#else
void foo() {
#endif
/* ... */
}

Here the function foo has two different beginnings, depending on
whethe the macro ‘BSD’ has been defined or not. To parse stuff like
this in its original form is all but impossible (to our knowledge, it’s
never been done).

Why is this so awful? Because it limits the amount of intelligence
we can put into our programming environments. Most Unix pro-
grammers aren’t used to having such environments and don’t know
what they’re missing, but there are all kinds of extremely useful fea-
tures that can easily be provided when automated analysis of source
code is possible.

Let’s look at an example. For most of the time that C has been
around, the preprocessor has been the only way to get expressions
open-coded (compiled by being inserted directly into the instruction
stream, rather than as a function call). For very simple and com-
monly used expressions, open-coding is an important efficiency tech-
nique. For instance, min, which we were just talking about above, is
commonly defined as a preprocessor macro:

#define min(x,y) ((x) < (y)? (x) : (y))

Suppose you wanted to write a utility to print a list of all functions in
some program that reference min. Sounds like a simple task, right?
Free download pdf