Warum lässt sich `int ;` in C gut kompilieren, aber nicht in C++?
Lesezeit: 3 Minuten
Destruktor
Betrachten Sie das folgende Programm (siehe Live-Demo hier).
#include <stdio.h>
int main(void)
{
int ; // Missing variable name
puts("Surprise");
}
Mein Compiler, gcc 4.8.1, gibt die folgende Warnung aus:
[Warning] nutzloser Typname in leerer Deklaration [enabled by default]
Warum lässt es sich gut kompilieren? Sollte ich nicht einen Compiler-Fehler erhalten? g++ 4.8.1 gibt den folgenden Fehler aus, wenn ich es als C++-Programm kompiliere:
@Nawaz: Wird es explizit durch die Sprachspezifikation gesagt?
– Destruktor
22. Oktober 2015 um 4:47 Uhr
Im C++-Standard heißt es explizit: “[dcl.dcl]/5 In einem einfache Erklärungdie Wahl Init-Declarator-Liste kann nur weggelassen werden, wenn eine Klasse (Abschnitt 9) oder eine Aufzählung (7.2) deklariert wird, das heißt, wenn die decl-spezifizierer-seq enthält entweder a Klassenbezeichnerein ausgearbeiteter Typbezeichner mit einer Klassenschlüssel (9.1) oder ein Enum-Spezifizierer.” Ich bin mit dem C-Standard nicht gut genug vertraut, um Kapitel und Verse zu zitieren.
– Igor Tandetnik
22. Oktober 2015 um 4:54 Uhr
“Erzeugt eine Warnung” ist nicht “kompiliert gut”.
– n. 1.8e9-wo-ist-meine-Aktie m.
22. Oktober 2015 um 5:13 Uhr
Nun, Sie können mehrere Locals gleichzeitig definieren (int a, b, c;), Rechts? int ; sieht nur aus wie ein Sonderfall derselben Sache, mit 0 deklarierten Einheimischen: D
– Luan
22. Oktober 2015 um 12:31 Uhr
Neu kompilieren mit -Werror
– David Konrad
22. Oktober 2015 um 23:07 Uhr
n. 1.8e9-wo-ist-meine-Aktie m.
Die C-Norm sagt
Eine andere Deklaration als eine static_assert-Deklaration muss mindestens einen Deklarator (anders als die Parameter einer Funktion oder die Mitglieder einer Struktur oder Vereinigung), ein Tag oder die Mitglieder einer Enumeration deklarieren.
sagt C++
In einer einfachen Deklaration kann die optionale Init-Declarator-Liste nur weggelassen werden, wenn eine Klasse (Klausel 9) oder eine Aufzählung deklariert wird.
Ein Verstoß dagegen in beiden Sprachen erfordert eine Diagnose. Die Standards sprechen nicht über Compilerfehler oder Warnungen. Eine Warnung ist eine Diagnose.
Können Sie klarstellen, ob der Standard eine Übersetzung verlangt, um bei bestimmten Verstößen zu scheitern? Ein “Fehler” könnte als eine Verletzung definiert werden, die eine Diagnose und einen Fehler erzeugt, und eine “Warnung” ist eine Verletzung, die eine Diagnose und keinen Fehler erzeugt.
– Damian Yerrick
22. Oktober 2015 um 15:24 Uhr
@tepples Nein, der Standard erfordert nur eine Diagnose. Es erfordert nicht (erlaubt aber), dass ein ungültiges Programm abgelehnt wird.
– n. 1.8e9-wo-ist-meine-Aktie m.
22. Oktober 2015 um 15:44 Uhr
es bedeutet, dass zb struct { int a; }; deklariert ein Strukturmitglied, aber das ist nicht genug.
– n. 1.8e9-wo-ist-meine-Aktie m.
23. Oktober 2015 um 22:54 Uhr
@nm: Hier ist also der Name der Struktur erforderlich. Rechts?
– Destruktor
24. Oktober 2015 um 8:41 Uhr
Es wird entweder ein Tag oder ein Deklarator benötigt. Etikett ist struct a { ... }. und Deklarator ist struct { ...} a. Ein Deklarator kann ein Variablenname oder ein Typedef-Name sein (falls das Schlüsselwort typedef vorhanden ist).
– n. 1.8e9-wo-ist-meine-Aktie m.
24. Oktober 2015 um 11:41 Uhr
Ameise
Ihr Code ist sowohl in C als auch in C++ illegal (dh fehlerhaft, schlecht geformt, gegen Einschränkungen verstoßend). Der Grund, warum Sie in einer Sprache eine “Warnung” und in einer anderen einen “Fehler” erhalten, ist nur eine Eigenart Ihres Compilers und Ihres Compiler-Setups. Schließlich unterscheiden beide Sprachen formal nicht wirklich zwischen „Warnungen“ und „Fehlern“. GCC ist unter seinen Standardeinstellungen im C-Modus freizügiger (hauptsächlich aus historischen Gründen).
Verwenden -pedantic-errors in GCC, und Sie erhalten auch einen “Fehler” im C-Code. (Beachten Sie, dass -pedantic-errors wandelt nicht einfach blind alle “Warnungen” in “Fehler” um. Es wird versucht, nur tatsächliche zu melden Beschränkungsverletzungen als “Fehler”.)
Yu Hao
Die Syntax der Deklaration ist definiert als (Weglassen Init-Declarator-Liste und Init-Deklarator):
Beachten Sie, dass Deklarationsbezeichner ist rekursiv definiert, aber jeweils mit einem opt gibt an, dass es optional ist.
Auch die folgende Klausel 6 besagt:
Die Deklarationsbezeichner bestehen aus einer Folge von Bezeichnern, die die Verknüpfung, die Speicherdauer und einen Teil des Typs der Entitäten angeben, die die Deklaratoren bezeichnen. Die initdeclarator-list ist eine durch Kommas getrennte Folge von Deklaratoren, von denen jeder zusätzliche Typinformationen oder einen Initialisierer oder beides haben kann. Die Deklaratoren enthalten die Bezeichner (wenn überhaupt) deklariert werden.
Beachte die Wörter wenn überhaupt.
10159100cookie-checkWarum lässt sich `int ;` in C gut kompilieren, aber nicht in C++?yes
@Nawaz: Wird es explizit durch die Sprachspezifikation gesagt?
– Destruktor
22. Oktober 2015 um 4:47 Uhr
Im C++-Standard heißt es explizit: “[dcl.dcl]/5 In einem einfache Erklärungdie Wahl Init-Declarator-Liste kann nur weggelassen werden, wenn eine Klasse (Abschnitt 9) oder eine Aufzählung (7.2) deklariert wird, das heißt, wenn die decl-spezifizierer-seq enthält entweder a Klassenbezeichnerein ausgearbeiteter Typbezeichner mit einer Klassenschlüssel (9.1) oder ein Enum-Spezifizierer.” Ich bin mit dem C-Standard nicht gut genug vertraut, um Kapitel und Verse zu zitieren.
– Igor Tandetnik
22. Oktober 2015 um 4:54 Uhr
“Erzeugt eine Warnung” ist nicht “kompiliert gut”.
– n. 1.8e9-wo-ist-meine-Aktie m.
22. Oktober 2015 um 5:13 Uhr
Nun, Sie können mehrere Locals gleichzeitig definieren (
int a, b, c;
), Rechts?int ;
sieht nur aus wie ein Sonderfall derselben Sache, mit 0 deklarierten Einheimischen: D– Luan
22. Oktober 2015 um 12:31 Uhr
Neu kompilieren mit
-Werror
– David Konrad
22. Oktober 2015 um 23:07 Uhr