C bites / programming style

Ray Butterworth rbutterworth at watmath.UUCP
Tue Sep 17 00:02:41 AEST 1985


> How about the following:
> 
> #define cycle for(;;) {
> #define endcycle }
> #define then {
> #define otherwise } else {
> #define elseif } else if 
> #define endif }
> #define exitwhen(exp) if (exp) break;
> #define exitunless(exp) if (!(exp)) break;
> 
> We can then write
> 
>   cycle
>       exitwhen(cond1)
>       if (cond2) then
>           stuff1
>       elseif (cond3) then
>           stuff2
>       otherwise
>          stuff3
>       endif
>   endcycle

Looks nice, but it might end up causing more problems than it
solves.  It has the form of an extension of the C language,
but this can be misleading since the compiler doesn't really know
about it.  To anyone looking at the code, the "endcycle" in the
last line obviously matches the "cycle" in the first.  Unfor-
tunately the compiler never sees these keywords, only the "{"
and "}".  You could just as easily have put an "endif" in place
of the "endcycle" without getting any complaint from the
compiler which would produce the correct code despite the mistake.

What happens when you accidentaly mess up the compound if
statement so that the braces don't quite match?  The compiler
won't complain until half way down the next page, and you won't
have a clue that the "endcycle" actually matches one of the "then"
keywords.  And you have lost the ability to use VI's % command
to tell you which "{" matches which "}".

Or consider an even worse example of this type of thing which will
compile and lint without error and might even execute correctly
some of the time (at least enough to pass the tests before release).

    cycle
        c=getchar();
        startswitch(c)
            default:
                exitwhen(++counter>LIMIT);
                putchar(BEEP);
                break;
            case EOF:
                exitwhen(ferror(stdin));
            case '\n':
                return;
            case BLAT:
            case BLORT:
            etc.
                dosomething();
                break;
            etc.
        endswitch
    endcycle
    an_error();

How obvious is it that the "exitwhen" really generates a "break"
that applies to the "case" and not to the "cycle"?

The use of "break" for both "case" and "for" control is a
limitation built into the C language.  So is the use of "}"
to end the compound statements following both a "switch" and
a "for".  These are features that C programmers have to live with.

Using #defines to make C look like "it should" doesn't solve the
problem, it only hides it, making it even harder to find when it
occurs.  If you really want these extensions to C, then either
they should be added to the compiler or a separate pre-processor
should be written which knows how to match "cycle" with "endcycle"
and which can issue appropriate error messages when they don't match.



More information about the Comp.lang.c mailing list