The following example is illegal C program, which is confusing and shows that a declaration is not a statement in C language.
int main() {
if (1) int x;
}
I've read the specification of C (N2176) and I know C language distinguish declaration and statement in the syntax specification. I told my teacher who teaches compiler, and he seems not believe it and I cannot convince him unless I showed him the specification.
So, I am also really confused. Why C is designed like this? Why a declaration is not a statement in C? How to convince someone of the reason of this design?
Because there is no apparent grammatical or technical semantic reason that a declaration cannot appear wherever a statement may appear, this appears to be largely due to history and lack of utility.
Statements enter the C grammar in the function-definition rule, in which a compound-statement appears. A compound-statement allows a statement. Then inspecting the replacements for a statement reveals the places where a statement may appear but a declaration may not:
:
.)
of an if
or a switch
or after an else
.)
of a while
or for
or after a do
.The following is not a formal analysis of the grammar, but it appears the places where a statement may appear but a declaration may not are quite limited: After the :
that ends a label, after a keyword (else
or do
) or after the closing )
for a (
that immediately follows a keyword (if
, switch
, while
, or for
). These seem to me like unambiguous points in the grammar, where it should be as easy to distinguish declarations and statements as it is to do so after a ;
in a compound-statement.
Therefore, I do not think there is a grammatical reason not to allow a declaration to appear anywhere a statement may appear (or, equivalently, to define a declaration as a kind of statement).
Now consider the semantic effects of allowing declarations in the places where currently a statement may appear but a declaration may not.
In the case of a labeled-statement, where we desired to have label: declaration
, we can use label: ; declaration
, where we have inserted a null statement after the :
. The result is a defined code sequence with semantic effect equivalent to what we would desire to have by allowing a declaration immediately after the label.
In the other cases, where we desire to have declaration
, we can use { declaration }
. Again, the result is a defined code sequence with semantic effect equivalent to what we would desire to have by allowing a bare declaration. That effect is minimal; any expressions in the declaration (in array declarators or initializers) will be evaluated, but anything that is declared goes out of scope immediately. Note that even if the scope were not ended by the closing }
, it is ended by the fact that the C standard defines each of these places to be a block. (C 2018 6.8.4 3 says the substatement of a selection-statement is a block, and 6.8.5 5 says the loop body of an iteration-statement is a block.)
Nonetheless, this shows there is no technical semantic impediment to allowing a declaration wherever a statement may appear.
Since the grammar and semantics of C apparently do not preclude allowing a declaration to be a type of statement, we are left with reasons of history and utility. In C as described in the first edition of Kernighan and Ritchie’s The C Programming Language, the locations of declarations were limited. Inside functions, they could only appear at the start of a compound statement. A declaration could not follow a statement. As we see from modern C, there was no grammatical or semantic reason for this limitation; we can allow declarations anywhere within a compound statement. So it seems simply that, around 1978, work on the language had not progressed that far.
Similarly, it seems that current work on C has not gone to the point of allowing a declaration to appear anywhere a statement may appear, as if it were a type of statement, even though there may be no technical impediment. However, in this case, there is less motivation for loosening the rules. Of the above cases, the only one that is of much use is allowing a declaration in a labeled statement. And, as its desired effect is easily accomplished by inserting a null statement, there is likely insufficient motivation to change compilers and to advocate for the changes in the C committee.