Why was mixing declarations and code forbidden up until C99?

I have recently become a teaching assistant for a university course which primarily teaches C. The course standardized on C90, mostly due to widespread compiler support. One of the very confusing concepts to C newbies with previous Java experience is the rule that variable declarations and code may not be intermingled within a block (compound statement).

This limitation was finally lifted with C99, but I wonder: does anybody know why it was there in the first place? Does it simplify variable scope analysis? Does it allow the programmer to specify at which points of program execution the stack should grow for new variables?

I assume the language designers wouldn't have added such a limitation if it had absolutely no purpose at all.


Solution 1:

In the very beginning of C the available memory and CPU resources were really scarce. So it had to compile really fast with minimal memory requirements.

Therefore the C language has been designed to require only a very simple compiler which compiles fast. This in turn lead to "single-pass compiler" concept: The compiler reads the source-file and translates everything into assembler code as soon as possible - usually while reading the source file. For example: When the compiler reads the definition of a global variable the appropriate code is emitted immediately.

This trait is visible in C up until today:

  • C requires "forward declarations" of all and everything. A multi-pass compiler could look forward and deduce the declarations of variables of functions in the same file by itself.
  • This in turn makes the *.h files necessary.
  • When compiling a function, the layout of the stack frame must be computed as soon as possible - otherwise the compiler had to do several passes over the function body.

Nowadays no serious C compiler is still "single pass", because many important optimizations cannot be done within one pass. A little bit more can be found in Wikipedia.

The standard body lingered for quite some time to relax that "single-pass" point in regard to the function body. I assume, that other things were more important.

Solution 2:

It was that way because it had always been done that way, it made writing compilers a little easier, and nobody had really thought of doing it any other way. In time people realised that it was more important to favour making life easier for language users rather than compiler writers.

I assume the language designers wouldn't have added such a limitation if it had absolutely no purpose at all.

Don't assume that the language designers set out to restrict the language. Often restrictions like this arise by chance and circumstance.

Solution 3:

I guess it should be easier for a non-optimising compiler to produce efficient code this way:

int a;
int b;
int c;
...

Although 3 separate variables are declared, the stack pointer can be incremented at once without optimising strategies such as reordering, etc.

Compare this to:

int a;
foo();
int b;
bar();
int c;

To increment the stack pointer just once, this requires a kind of optimisation, although not a very advanced one.

Moreover, as a stylistic issue, the first approach encourages a more disciplined way of coding (no wonder that Pascal too enforces this) by being able to see all the local variables at one place and eventually inspect them together as a whole. This provides a clearer separation between code and data.