"if" statement syntax differences between C and C++

if (1) int a = 2;

This line of code is valid C++ code (it compiles at the very least) yet invalid C code (doesn't compile). I know there are differences between the languages but this one was unexpected.

I always thought the grammar was

if (expr) statement

but this would make it valid in both.

My questions are:

  1. Why doesn't this compile in C?
  2. Why does this difference exist?
8023 次浏览

This is a subtle and important difference between C and C++. In C++ any statement may be a declaration-statement. In C, there is no such thing as a declaration-statement; instead, a declaration can appear instead of a statement within any compound-statement.

From the C grammar (C17 spec):

compound-statement: "{" block-item-listopt "}"
block-item-list: block-item | block-item-list block-item
block-item: declaration | statement

From the C++ grammar (C++14 spec):

compound-statement: "{" statement-seqopt "}"
statement-seq: statement | statement-seq statement
statement: ... | declaration-statement | ...

It is not clear why this difference exists, it is just the way the languages evolved. The C++ syntax dates all the way back to (at least) C++85. The C syntax was introduced sometime between C89 and C99 (in C89, declarations had to be at the beginning of a block)


In the original 85 and 89 versions of C++, the scope of a variable defined in a declaration-statement was "until the end of the enclosing block"). So a declaration in an if like this would not immediately go out of scope (as it does in more recent versions) and instead would be in scope for statements following the if in the same block scope. This could lead to problems with accessing uninitialized data when the condition is false. Worse, if the var had a non-trivial destructor, that would be called when the scope ended, even if it had never been initialized! I suspect trying to avoid these kinds of problems is what led to C adopting a different syntax.

It's because C and C++ define statement differently.

In C, declarations are not classified as statements. A C compound statement consists of an opening {, an option list of block-items, and a closing }, where a block-item either a declaration or a statement. (This was changed in C99, when C added the ability to mix declarations and statements within a block.)

In C++, a declaration is classified as a statement (but only if it's inside a compound statement). This allows a simpler definition of a compound-statement: it's a {, followed by an optional list of statements, followed by a }.

The difference doesn't have much practical effect; it's always possible to work around it. One effect is that it's legal in C++ for a declaration immediately follow a case label, but in C it's not legal.

In C, a declaration and a statement are distinct entities.

In C++, a a subset of declarations called a block-declaration is a type of statement, specifically it is a declaration-statement. These include simple declarations like int a=2.

Chris's answer (and others) shows how the grammar is different.

I want to point out that if (1) int a = 2; doesn't make sense in C but it does in C++. Since we don't have a block but just 1 statement/declaration there is no possible further use of the variable declared (it goes out of scope immediately). In C this would make no sense to allow, but in C++ constructors and destructors can have side effects, so defining and initializing a variable that goes out of scope immediately can be useful and must be allowed.