Deklarationen/Definitionen als Anweisungen in C und C++

Lesezeit: 6 Minuten

Benutzeravatar von Zebrafish
Zebrafisch

Ich war verwirrt, als dies nicht in C kompiliert wurde:

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 habe eine Weile nur verblüfft gestarrt, bis ich mich an eine Antwort hier auf SO erinnerte, wie in C und C++ verschiedene Dinge als “Anweisungen” betrachtet werden. Dies bezog sich auf eine Switch-Anweisung. Sowohl in C als auch in C++ muss ein “Statement” nach der for-Schleife in Klammern stehen. Dies kann sowohl durch Hinzufügen eines Semikolons als auch durch Erstellen eines { } verschnörkelten Klammerblocks erfolgen.

In C++ “int a = 7;” wird als Deklaration, Definition und Initialisierung betrachtet. In CI wird glauben, dass dies alles auch berücksichtigt wird, in C wird es jedoch nicht als “Aussage” betrachtet.

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

  • @NathanOliver Ich habe zum ersten Mal auf meinem Visual Studio 2017 sowohl C- als auch C++-Compiler bemerkt, aber ich weiß, dass dies kein großartiges Beispiel für Konformität ist, also habe ich es auf onlinegdb.com versucht und in beiden kompiliert. Hier ist ein Beispiel: onlinegdb.com/SysJyUGnf Tut mir leid, ich bin mir nicht sicher, ob das GCC verwendet oder was. Aber wenn Sie oben rechts zu C++ wechseln, sehen Sie den Unterschied zwischen den beiden.

    – Zebrafisch

    16. April 2018 um 16:29 Uhr

  • Welche Art von Antwort suchen Sie? Eine Erklärung des C++-Komitees darüber, warum sie sich entschieden haben, Dinge anders zu machen als C?

    – Melpomen

    16. April 2018 um 16:30 Uhr

  • @melpomene Ich fange an zu verstehen, dass eine Definition in einer Sprache nicht dieselbe in einer anderen Sprache haben muss, deshalb ist es eine andere Sprache. Nur dass ich in C und C++, da sie so ähnlich sind, erwartet habe, dass etwas so Grundlegendes wie eine “Anweisung” ein ähnliches Konzept ist, aber dies ist offensichtlich eine große Ausnahme. Ich habe dies zum ersten Mal in einer ziemlich beliebten Frage zum Überspringen der Initialisierung in C- und C++-Switch-Anweisungen bemerkt.

    – Zebrafisch

    16. April 2018 um 16:33 Uhr

  • Es gibt viele “Dialekte” von C. Die frühesten erlauben nicht einmal bereichsbezogene Variablen. Sie müssen alle Variablen vor dem gesamten Code deklarieren. “K&R” C zum Beispiel ist radikal anders. Sie sollten angeben, welche Version von C Sie verwenden. (C99 ist bei modernen Compilern am häufigsten).

    – Tiger4Hire

    16. April 2018 um 17:46 Uhr

Benutzeravatar von AndyG
AndyG

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

Wenn die Unteranweisung in einer Iterationsanweisung eine einzelne Anweisung und keine zusammengesetzte Anweisung ist, ist sie so, als wäre sie in eine zusammengesetzte Anweisung umgeschrieben worden, 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.

Außerdem ist die Definition von a Aussage in C++ geändert, um a einzuschließen Deklarationsanweisungalso selbst wenn die obige Änderung nicht vorgenommen würde, wäre sie immer noch legal.


Der Grund, warum das Hinzufügen von geschweiften Klammern funktioniert, ist, dass Ihre Deklaration jetzt zu a wird Zusammengesetzte Aussage die Deklarationen enthalten können.

Sie dürfen eine haben Kennung in einem Schleifenkörper ohne geschweiften Klammern, also können Sie stattdessen Folgendes tun:

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

  • Aha. Ihr Zitat bezieht sich auf eine Iteration, jedoch int a = 7; still wird nicht als Anweisung in einer switch-Anweisung akzeptiert. Dort heißt es: „Ein Label kann nur Teil einer Aussage sein und eine Deklaration ist keine Aussage“. Scheint nicht nur für Iterationen zu gelten, obwohl ich mich vielleicht missverstehe.

    – Zebrafisch

    16. April 2018 um 16:40 Uhr

  • Das Zitat zur Iteration (z. B. for, while) muss auch für case-Labels gelten. In C++ case 1: int a = 7; muss in C++ als zusammengesetzte Anweisung gesehen werden, vermute ich? Während in C es nicht ist.

    – Zebrafisch

    16. April 2018 um 16:45 Uhr

  • @Zebrafish: Dies kann hilfreich sein stackoverflow.com/q/92396/27678

    – AndyG

    16. April 2018 um 16:54 Uhr

Benutzeravatar von eerorika
Erorika

In C++ ist 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, die Deklarationen und Anweisungen sind. Ebenso sind einfache Deklarationen Init-Anweisungen. Nicht alle Erklärungen sind jedoch Aussagen. Die Grammatik der Deklarationen enthält Dinge, die nicht in der Liste der Anweisungen stehen:

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 geht noch einige Seiten weiter.


In C ist eine Anweisung (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 Deklarationen gibt, die Anweisungen sind.


Also die Bedeutung von Aussage unterscheidet sich deutlich in den Sprachen. Statement in C++ scheint eine breitere Bedeutung zu haben als Statement in C.

Benutzeravatar von Abhishek Keshri
Abhishek Keshri

Gemäß cpReferenz, C++ umfasst folgende Arten von statements:

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

Während C berücksichtigt folgende Arten von statements:

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

Wie Sie sehen können, werden Deklarationen nicht berücksichtigt statements in C, 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

  • Ich sehe user2079303 und Sie haben dieselbe Antwort eingegeben. Dies und das andere erklärt meiner Meinung nach genau, worum es geht. Vielen Dank.

    – Zebrafisch

    16. April 2018 um 16:51 Uhr

  • Ich helfe gerne 🙂 Ja, ich habe gepostet und festgestellt, dass er die gleiche Antwort hat, Zeitunterschied weniger als eine Minute, lol;)

    – Abhishek Keshri

    16. April 2018 um 16:56 Uhr

  • Aus Gründen der Konsistenz würde ich die zusammengesetzte Anweisung der Funktionsdefinition auch im C++-Beispiel kommentieren.

    – Erorika

    16. April 2018 um 17:04 Uhr

In C++ sind Deklarationen Anweisungen, während Deklarationen in C 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 Unteranweisung der Schleife sein. Es ist jedoch eine Erklärung.

Sie könnten den Code in C kompilieren, indem Sie beispielsweise die zusammengesetzte Anweisung verwenden

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

obwohl der Compiler eine Diagnosemeldung ausgeben kann, die besagt, dass die Variable a ist nicht benutzt.

Eine weitere Konsequenz, dass Deklarationen in C keine Anweisungen sind. Sie dürfen in C kein Label vor eine Deklaration setzen. 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;
}

kompiliert nicht in C, obwohl es als C++-Programm kompiliert wird. Wenn jedoch eine Null-Anweisung nach dem Label platziert wird, 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;
}

1401770cookie-checkDeklarationen/Definitionen als Anweisungen in C und C++

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy