int main()
{
int var = 0;; // Typo which compiles just fine
}
Warum sind leere Ausdrücke in C/C++ zulässig?
Wie sonst könnte assert(foo == bar);
zu nichts kompilieren, wenn NDEBUG
ist definiert?
-
Nun, mir fällt jetzt ein, dass ich es zu so etwas wie kompilieren lasse
0
oder((void) 0)
wäre wahrscheinlich auch ok, aber trotzdem…– j_random_hacker
14. November 11 um 20:04 Uhr
-
assert() könnte ein Makro sein und kehrt in NDEBUG zu einem Ausdruck ohne Seiteneffekte zurück, z. B. (void)0;
– Nick
5. Dezember 17 um 17:04 Uhr
Auf diese Weise drücken sich C und C++ aus NOP.
-
Was bei Mikrocontroller-Systemen mit knappem Budget von größter Bedeutung ist.
– jpinto3912
5. Mai 09 um 13:34 Uhr
-
@ jpinto3912: In der Tat
;
wird mit ziemlicher Sicherheit nach unten kompilieren gar keine Anleitung, anstatt auf die der ZielplattformNOP
Anweisung.– j_random_hacker
14. August ’10 um 4:00 Uhr
-
Das bezweifle ich. Eher ein intrinsischer oder asm. Keine Anweisungen != NOP.
– Nick
5. Dezember 17 um 17:02 Uhr
Dan Fego
Ich bin kein Sprachdesigner, aber die Antwort, die ich geben würde, lautet: “Warum nicht?” Aus Sicht des Sprachdesigns möchte man, dass die Regeln (dh die Grammatik) so einfach wie möglich sind.
Ganz zu schweigen davon, dass “leere Ausdrücke” Verwendungen haben, dh
for (i = 0; i < Wahnsinnszahl; i++);
Will dead-wait (keine gute Verwendung, aber dennoch eine Verwendung).
BEARBEITEN: Wie in einem Kommentar zu dieser Antwort erwähnt, würde wahrscheinlich jeder Compiler, der sein Salz wert ist, dies tun nicht Beschäftigt warten Sie auf diese Schleife und optimieren Sie sie weg. Wenn jedoch etwas Nützlicheres im for-Kopf selbst (außer i++) vorhanden wäre, was ich (seltsamerweise) beim Durchlaufen von Datenstrukturen gesehen habe, dann könnte ich mir vorstellen, dass Sie immer noch eine Schleife mit einem leeren Körper konstruieren könnten (indem Sie / Missbrauch des „für“-Konstrukts).
-
Wird das wirklich warten? Kann der Compiler die Schleife wegoptimieren, da nichts passiert?
– Tom
5. Mai 09 um 11:53 Uhr
-
Gute Frage. Jetzt wo du es erwähnst, ich weiß es nicht. Ich weiß nur, dass es sollen. 🙂
– Dan Fego
5. Mai 09 um 11:55 Uhr
-
@Tom: Gute Frage. Zumindest in C++ ist die Ausführungszeit laut Standard nicht explizit Teil des “beobachtbaren Verhaltens” des Systems, daher nehme ich theoretisch an, dass ein Compiler dies optimieren könnte. Wenn i jedoch flüchtig ist, ist diese Optimierung verboten.
– j_random_hacker
5. Mai 09 um 11:58 Uhr
Thomas Padron-McCarthy
Sie möchten in der Lage sein, Dinge zu tun wie
while (fnorble(the_smurf) == FAILED)
;
und nicht
while (fnorble(the_smurf) == FAILED)
do_nothing_just_because_you_have_to_write_something_here();
Aber! Bitte schreiben Sie die leere Anweisung nicht wie folgt in dieselbe Zeile:
while (fnorble(the_smurf) == FAILED);
Das ist eine sehr gute Möglichkeit, den Leser zu verwirren, da man leicht das Semikolon übersieht und daher denkt, die nächste Zeile sei der Schleifenkörper. Denken Sie daran: Beim Programmieren geht es wirklich um Kommunikation – nicht mit dem Compiler, sondern mit anderen Leuten, die Ihren Code lesen werden. (Oder mit sich selbst, drei Jahre später!)
Jason König
OK, ich füge dies dem Worst-Case-Szenario hinzu, das Sie möglicherweise tatsächlich verwenden:
for (int yy = 0; yy < nHeight; ++yy) {
for (int xx = 0; xx < nWidth; ++xx) {
for (int vv = yy - 3; vv <= yy + 3; ++vv) {
for (int uu = xx - 3; uu <= xx + 3; ++uu) {
if (test(uu, vv)) {
goto Next;
}
}
}
Next:;
}
}
-
+1 für das nützliche Beispiel: Da goto-Labels eine Anweisung haben müssen, aber in den seltenen Fällen, in denen Sie ein goto benötigen, wird das Label oft nur am Ende einer Schleife benötigt, sodass Sie eine NOP-Anweisung benötigen. Sie können gegen gotos wettern, aber es ist gelegentlich vorzuziehen (UND lesbarer), ein goto zu verwenden, um tief verschachtelte Schleifen zu verlassen, anstatt zusätzliche Variablen und if () -Anweisungen zu haben, um jede Schleife einzeln zu verlassen.
– Darren
6. November 14 um 17:02 Uhr
Tom
Ich weiß ehrlich gesagt nicht, ob dies der wahre Grund ist, aber ich denke, dass es sinnvoller ist, vom Standpunkt eines Compiler-Implementierers darüber nachzudenken.
Große Teile von Compilern werden von automatisierten Tools erstellt, die spezielle Klassen von Grammatiken analysieren. Es scheint sehr natürlich, dass nützliche Grammatiken leere Anweisungen zulassen würden. Es scheint unnötige Arbeit zu sein, einen solchen “Fehler” zu erkennen, wenn er die Semantik Ihres Codes nicht ändert. Die leere Anweisung wird nichts bewirken, da der Compiler keinen Code für diese Anweisungen generiert.
Es scheint mir, dass dies nur ein Ergebnis von “Repariere nichts, das nicht kaputt ist” …
-
+1 für das nützliche Beispiel: Da goto-Labels eine Anweisung haben müssen, aber in den seltenen Fällen, in denen Sie ein goto benötigen, wird das Label oft nur am Ende einer Schleife benötigt, sodass Sie eine NOP-Anweisung benötigen. Sie können gegen gotos wettern, aber es ist gelegentlich vorzuziehen (UND lesbarer), ein goto zu verwenden, um tief verschachtelte Schleifen zu verlassen, anstatt zusätzliche Variablen und if () -Anweisungen zu haben, um jede Schleife einzeln zu verlassen.
– Darren
6. November 14 um 17:02 Uhr
ib.
Offensichtlich ist es so, dass wir Dinge wie sagen können
for (;;) {
// stuff
}
Wer könnte ohne das leben?
-
Das ist kein gutes Beispiel, weil zum Beispiel das zweite Semikolon nicht verwendet wird, um eine Anweisung zu beenden. Die zweite Klausel des for ist ein Ausdruck; und das Leerlassen wird als Sonderfall behandelt und ist damit gleichbedeutend mit wahr.
– neues Konto
5. Mai 09 um 18:06 Uhr
-
Das ist eigentlich ein schlechtes und irrelevantes Beispiel. Der
;
innerhalb der Kopfzeile vonfor
nichts mit dem gemein haben;
in der Frage des OP. Was du drin hastfor
Header sind überhaupt keine Anweisungen. Und das;
in obigemfor
sind keine “leeren Aussagen”. Der;
infor
sind einfach fest codierte Zeichen vonfor
Syntax ohne besondere Bedeutung. Nur der erste Abschnitt vonfor
Header wird in der Sprachspezifikation als “Anweisung” bezeichnet, aber selbst das ist eine besondere Art vonfor
-spezifische Pseudoaussage mit eigener dedizierter Grammatik.– Ant
24. Oktober 13 um 23:13 Uhr
-
… Mit anderen Worten, die Tatsache, dass
for(;;)
is legal hat absolut nichts damit zu tun, dass leere Aussagen legal sind. Die beiden werden durch ihre eigenen, absolut unabhängigen Teile der Grammatik- und Sprachspezifikation beschrieben.– Ant
24. Oktober 13 um 23:14 Uhr
-
Und bei der ursprünglichen Frage geht es eigentlich um Aussagen, nicht um Ausdrücke. Das OP hat den Begriff “Ausdruck” anscheinend falsch verwendet, weil sie den Unterschied zwischen Ausdrücken und Anweisungen nicht gelernt haben.
– Ant
24. Oktober 13 um 23:15 Uhr
-
Ich kann nicht glauben, dass 13 Personen diesem +1 gegeben haben.
– Tanveer Badar
3. Oktober 20 um 5:37 Uhr
.
Holen Sie sich einen Mikrocontroller mit einer geringen Anzahl von Timern, und bald werden Sie NOP-Befehle verwenden wollen … implementiert mit ; auf C (C++ ist in diesem Szenario unwahrscheinlich)
– jpinto3912
5. Mai 09 um 13:37 Uhr
@RA ein ;; ist kein Leerzeichen vor einer Compiler-Optimierung: es ist ein NOP.
– jpinto3912
5. Mai 09 um 13:38 Uhr
@jpinto: Denke, du hast meinen Kommentar falsch gelesen.
– Haiin
5. Mai 09 um 13:44 Uhr
Technisch gesehen ist dies kein leerer Ausdruck (was C/C++ nicht allow), aber das zweite Semikolon ist ein Null-Ausdruck. Wenn Sie zum Beispiel in einem der Zweige eines bedingten (ternären) Ausdrucks (im leeren Kontext) nichts tun wollen, sind Sie gezwungen, etwas Unnützes zu schreiben (das außerdem mit dem übereinstimmen muss, was im anderen Zweig steht).
– Marc van Leeuwen
11. Juli 21 um 12:55 Uhr