44

I was confused when this wouldn't compile in C:

int main()
{
    for (int i = 0; i < 4; ++i)
        int a = 5; // A dependent statement may not be declaration

    return 0;
}

I'm used to C++ where this will compile. I just stared dumbfounded for a while until I remembered an answer here on SO about how in C and C++ different things are considered "statements". This was in regard to a switch statement. A "statement" after the for loop brackets must be present both in C and C++. This can be done in both either adding a semicolon or creating a { } squiggly bracket block.

In C++ "int a = 7;" is considered a declaration, definition, and initialisation. In C I believe it is also considered all of these, however in C it is not considered a "statement".

Could someone exactly clarify why in C this isn't a statement whereas in C++ it is? This is confusing my concept of what a statement is, because one language says it is, and another says it isn't, so I'm kind of confused.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • @NathanOliver I first noticed on my Visual Studio 2017, both C and C++ compilers, but I know this isn't a great example of compliance, so I tried at onlinegdb.com, compiling in both, Here is an example, https://onlinegdb.com/SysJyUGnf Sorry, not sure if that's using GCC or what. But if you switch to C++ on the top right you'll see the difference between the two. – Zebrafish Apr 16 '18 at 16:29
  • 1
    What kind of answer are you looking for? A statement from the C++ committee on why they decided to do things differently from C? – melpomene Apr 16 '18 at 16:30
  • 1
    @melpomene I'm starting to get the point, one definition in one language doesn't have to have the same in another language, that's why it's another language. Just that in C and C++, being so similar, I expected something as basic as a "statement" to be a similar concept, but this is obviously big exception. I first noticed this in a pretty popular question about jumping over initialisation in C and C++ switch statement. – Zebrafish Apr 16 '18 at 16:33
  • There are many "dialects" of C. The earliest ones don't even allow scoped variables at all. You have to declare all variables before all the code. "K&R" C for example is radically different. You should state which version of C you are using. (C99 is most common on modern compilers). – Tiger4Hire Apr 16 '18 at 17:46

4 Answers4

17

C++ allowed that the "substatement" of an iteration statement was implicitly a compound statement ([stmt.iter])

If the substatement in an iteration-statement is a single statement and not a compound-statement, it is as if it was rewritten to be a compound-statement containing the original statement. Example:

while (--x >= 0)
   int i;

can be equivalently rewritten as

while (--x >= 0) {
   int i;
}

the C standard does not have this language.

Additionally, the definition of a statement changed in C++ to include a declaration statement, so even if the above change wasn't made, it would still be legal.


The reason that adding braces makes it work is because your declaration now becomes a compound-statement which can include declarations.

You are allowed to have an identifier in a loop body without braces, so you can do this instead:

int a = 5;
for (int i = 0; i < 4; ++i)
    a;
AndyG
  • 39,700
  • 8
  • 109
  • 143
  • I see. Your quote relates to an iteration, however int a = 7; still isn't accepted as a statement in a switch statement. It says: "a label can only be part of a statement and a declaration is not a statement". Doesn't seem to apply only to iterations, though I may be misunderstanding. – Zebrafish Apr 16 '18 at 16:40
  • That quote about iteration (eg for, while) must also apply to case labels, In C++ case 1: int a = 7; must be seen in C++ as a compound statement I'm guessing? Whereas in C it isn't. – Zebrafish Apr 16 '18 at 16:45
  • @Zebrafish: this may be helpful https://stackoverflow.com/q/92396/27678 – AndyG Apr 16 '18 at 16:54
  • For the first example, if declaration is not treated as a statement, will it still be a "single statement"? – TYeung Apr 16 '23 at 07:55
16

In C++, a statement is (C++17 standard draft)

excerpt from [gram.stmt]

statement:
    labeled-statement
    attribute-specifier-seqopt expression-statement
    attribute-specifier-seqopt compound-statement
    attribute-specifier-seqopt selection-statement
    attribute-specifier-seqopt iteration-statement
    attribute-specifier-seqopt jump-statement
    declaration-statement
    attribute-specifier-seqopt try-block

init-statement:
    expression-statement
    simple-declaration

declaration-statement:
    block-declaration

...

Note that there are declaration statements in C++, which are declarations, and are statements. Similarly, simple declarations are init statements. Not all declarations are statements though. The grammar of declarations contains things that are not in the list of statements:

excerpt from [gram.dcl]

declaration:
    block-declaration
    nodeclspec-function-declaration
    function-definition
    template-declaration
    deduction-guide
    explicit-instantiation
    explicit-specialization
    linkage-specification
    namespace-definition
    empty-declaration
    attribute-declaration

block-declaration:
    simple-declaration
    asm-definition
    namespace-alias-definition
    using-declaration
    using-directive
    static_assert-declaration
    alias-declaration
    opaque-enum-declaration

simple-declaration:
    decl-specifier-seq init-declarator-listopt ;
    attribute-specifier-seq decl-specifier-seq init-declarator-list ;
    attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt [ identifier-list ] initializer ;

...

The list of declaration grammars continues on for a few pages.


In C, a statement is (C11 standard draft)

excerpt from Statements and blocks

statement:
    labeled-statement
    compound-statement
    expression-statement
    selection-statement
    iteration-statement
    jump-statement

Note that there are no declarations that are statements in C.


So, the meaning of statement is clearly different in the languages. Statement in C++ appears to have a broader meaning than statement in C.

eerorika
  • 232,697
  • 12
  • 197
  • 326
9

According to cppreference, C++ includes following types of statements:

  1. expression statements;
  2. compound statements;
  3. selection statements;
  4. iteration statements;
  5. jump statements;
  6. declaration statements;
  7. try blocks;
  8. atomic and synchronized blocks

While C considers following types of statements:

  1. compound statements
  2. expression statements
  3. selection statements
  4. iteration statements
  5. jump statements

As you can notice, declarations are not considered statements in C, while it is not this case in C++.

For C++:

int main()
{                                     // start of a compound statement
    int n = 1;                        // declaration statement
    n = n + 1;                        // expression statement
    std::cout << "n = " << n << '\n'; // expression statement
    return 0;                         // return statement
}                                     // end of compound statement

For C:

int main(void)
{                          // start of a compound statement
    int n = 1;             // declaration (not a statement)
    n = n+1;               // expression statement
    printf("n = %d\n", n); // expression statement
    return 0;              // return statement
}                          // end of compound statement
Matt Reynolds
  • 787
  • 2
  • 9
  • 22
Abhishek Keshri
  • 3,074
  • 14
  • 31
  • I see user2079303 and you were typing the same answer. This and the other explains exactly what's going on in my opinion. Thanks. – Zebrafish Apr 16 '18 at 16:51
  • happy to help :) yeah I posted and notice he has got the same answer, time difference less than a minute ,lol ;) – Abhishek Keshri Apr 16 '18 at 16:56
  • I would annotate the compound statement of the function definition in C++ example as well, for consistency. – eerorika Apr 16 '18 at 17:04
2

In C++ declarations are statements while in C declarations are not statements. So according to the C grammar in this for loop

for (int i = 0; i < 4; ++i)
    int a = 5;

int a = 5; must be a substatement of the loop. However it is a declaration.

You could make the code to be compiled in C by using the compound statement as for example

for (int i = 0; i < 4; ++i)
{
    int a = 5;
}

though the compiler can issue a diagnostic message saying that the variable a is not used.

One more consequence that in C declarations are not statements. You may not place a label before a declaration in C. For example this program

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:
    int x = n;

    printf( "x == %d\n", x );

    if ( --n ) goto L1; 

    return 0;
}

does not compile in C though it compiles as a C++ program. However if to place a null-statement after the label then the program does compile.

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:;
    int x = n;

    printf( "x == %d\n", x );

    if ( --n ) goto L1; 

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335