Ich war verwirrt, als dies in C nicht kompiliert werden konnte:

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

    return 0;
}

Ich bin an C ++ gewöhnt, wo dies kompiliert wird. Ich starrte nur eine Weile verblüfft, bis ich mich an eine Antwort hier auf SO erinnerte, wie in C und C ++ verschiedene Dinge als "Aussagen" betrachtet werden. Dies betraf eine switch-Anweisung. Eine "Anweisung" nach den for-Schleifenklammern muss sowohl in C als auch in C ++ vorhanden sein. Dies kann entweder durch Hinzufügen eines Semikolons oder durch Erstellen eines {} schnörkellosen Klammerblocks erfolgen.

In C ++ "int a = 7;" wird als Deklaration, Definition und Initialisierung betrachtet. In C glaube ich, dass es auch als all dies betrachtet wird, aber in C wird es nicht als "Aussage" betrachtet.

Könnte jemand genau erklären, warum dies in C keine Aussage ist, während dies in C ++ der Fall ist? Dies verwirrt mein Konzept, was eine Aussage ist, weil eine Sprache sagt, dass es ist, und eine andere sagt, dass es nicht ist, also bin ich irgendwie verwirrt.

42
Zebrafish 16 Apr. 2018 im 19:21

4 Antworten

Beste Antwort

In C ++ lautet eine Anweisung (C ++ 17 Standardentwurf)

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

...

Beachten Sie, dass es in C ++ Deklarationsanweisungen gibt, bei denen es sich um Deklarationen und Anweisungen handelt. Ebenso sind einfache Deklarationen init-Anweisungen. Nicht alle Erklärungen sind Aussagen. Die Grammatik der Deklarationen enthält Dinge, die nicht in der Liste der Aussagen enthalten sind:

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 ;

...

Die Liste der Deklarationsgrammatiken wird einige Seiten lang fortgesetzt.


In C ist eine Aussage (C11 Standardentwurf)

excerpt from Statements and blocks

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

Beachten Sie, dass es in C keine Erklärungen gibt, die Aussagen sind.


Die Bedeutung von Anweisung unterscheidet sich also in den Sprachen deutlich. Anweisung in C ++ scheint eine breitere Bedeutung zu haben als Anweisung in C.

12
eerorika 21 Apr. 2018 im 20:56

C ++ erlaubte, dass die "Substatement" einer Iterationsanweisung implizit eine zusammengesetzte Anweisung war ([stmt.iter])

Wenn die Unteranweisung in einer Iterationsanweisung eine einzelne Anweisung und keine zusammengesetzte Anweisung ist, ist es so, als ob sie als zusammengesetzte Anweisung umgeschrieben wurde, die die ursprüngliche Anweisung enthält. Beispiel:

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

Kann äquivalent umgeschrieben werden als

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

Der C-Standard hat diese Sprache nicht.

Darüber hinaus wurde die Definition einer Anweisung in C ++ dahingehend geändert, dass sie eine Deklarationsanweisung enthält. Selbst wenn die obige Änderung nicht vorgenommen wurde, ist sie dennoch legal.


Das Hinzufügen von geschweiften Klammern funktioniert, weil Ihre Deklaration jetzt zu einer zusammengesetzten Anweisung wird, die Deklarationen enthalten kann.

Sie dürfen einen Bezeichner in einem Schleifenkörper ohne geschweifte Klammern haben, also können Sie dies stattdessen tun:

int a = 5;
for (int i = 0; i < 4; ++i)
    a;
16
AndyG 18 Apr. 2018 im 15:32

Laut cppreference enthält C ++ die folgenden Arten von statements:

  1. Ausdrucksanweisungen;
  2. zusammengesetzte Aussagen;
  3. Auswahlaussagen;
  4. Iterationsanweisungen;
  5. Sprunganweisungen;
  6. Deklarationserklärungen;
  7. versuche Blöcke;
  8. atomare und synchronisierte Blöcke

Während C die folgenden Arten von statements berücksichtigt:

  1. zusammengesetzte Aussagen
  2. Ausdrucksanweisungen
  3. Auswahlanweisungen
  4. Iterationsanweisungen
  5. Sprunganweisungen

Wie Sie feststellen können, werden Deklarationen in C nicht als statements betrachtet, während dies in C ++ nicht der Fall ist.

Für 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

Für 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
7
Matt Reynolds 12 Sept. 2019 im 03:09

In C ++ sind Deklarationen Anweisungen, während in C Deklarationen keine Anweisungen sind. Also nach der C-Grammatik in dieser for-Schleife

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

Int a = 5; muss eine Unteraussage der Schleife sein. Es ist jedoch eine Erklärung.

Sie können den zu kompilierenden Code in C erstellen, indem Sie beispielsweise die zusammengesetzte Anweisung verwenden

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

Der Compiler kann jedoch eine Diagnosemeldung ausgeben, die besagt, dass die Variable a nicht verwendet wird.

Eine weitere Konsequenz, die in C-Deklarationen keine Aussagen sind. Sie dürfen vor einer Deklaration in C kein Etikett platzieren. Zum Beispiel dieses Programm

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:
    int x = n;

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

    if ( --n ) goto L1; 

    return 0;
}

Wird nicht in C kompiliert, obwohl es als C ++ - Programm kompiliert wird. Wenn jedoch nach dem Label eine Null-Anweisung eingefügt werden soll, wird das Programm kompiliert.

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:;
    int x = n;

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

    if ( --n ) goto L1; 

    return 0;
}
2
Vlad from Moscow 16 Apr. 2018 im 17:24