[comp.lang.c] "smart" cpp

ok@quintus.UUCP (Richard A. O'Keefe) (04/13/88)

In article <1528@dataio.Data-IO.COM>, bright@Data-IO.COM (Walter Bright) writes:
> Here is a portion of a package to handle bit vectors in C. It demonstrates
> a reasonable use for allowing casts and sizeofs in preprocessor expressions.
...
> /* This code depends on 8 bit bytes. Put check in for this.	*/
> /* I don't care about 1's complement machines.			*/
> #if (unsigned char) -1 != 255
> #error	"bytes are not 8 bits"
> #endif

That has never been portable, if only because a great many C preprocessors
do not support "#error".  I tried something like this just now, and the
entire error message was
	FOO.c: 1: undefined control

May I point out that there is no need to do everything in the preprocessor?
What distinguishes the C preprocessor from the incredibly hairy things in
PL/I (compile-time procedures), Burroughs Algol, and SAIL (see TOPLAS some
years ago), is that it is supposed to be small, fast, and cheap, so that
you can afford to use it all the time whether you need it or not.

If you need something more complicated than cpp can help with, you can
use M4 (there is a public domain M4 in the mod.sources archives), or you
can write a C program which generates a .h file or whatever.  For example,
consider an FFT routine.  You don't want to call sin() and cos() at run
time, but you can't rely on the compiler optimising cos(1.0/pow(2.0,6))
to a constant, and cpp can't do it.  So you write a C program which calculates
the table and writes out the appropriate constants.

In this particular case, you might put something like

	real-prog: real-prog.c defs.h

	defs.h:	mk-defs
		mk-defs >defs.h

	mk-defs: mk-defs.c

in a make-file (there are versions of 'make' for MS-DOS and VMS),
and the mk-defs.c program would have this test as perfectly ordinary C:
	if ((unsigned char)(-1) != 255) {
	    fprintf(stderr, "unsigned char is not 8 bits\n");
	    exit(1);
	}