Zweck von while(1); Aussage in C

Lesezeit: 10 Minuten

Benutzeravatar von Abhijit K Rao
Abhijit K Rao

Welchen Zweck hat while(1); Dienen ? Mir ist bewusst while(1) (kein Semikolon) wird endlos wiederholt und ähnelt einer Spinlock-Situation. Allerdings sehe ich nicht wo while(1); könnte verwendet werden ?

Beispielcode

if(!condition)
{ 
  while(1);
}

Hinweis: Dies ist kein Fall von dowhile() oder schlicht while(1).

  • Es ist einfach ein weiteres Verfahren zum Bereitstellen einer Endlosschleife, die innerhalb ihres Codeblocks unterbrochen wird. Ähnlich zu for (;;). Es gibt zahlreiche Beispiele in den Manpages, wo Sie Endlosschleifen mit einem Later finden können break um die Schleife nach der gewünschten Anzahl von Iterationen zu verlassen

    – David C. Rankin

    18. Juni 2014 um 6:51 Uhr


  • @DavidC.Rankin a while(1); (beachten Sie das ; am Ende) Die Schleife hat keinen Körper, in dem eine Unterbrechung stattfinden könnte

    – mch

    18. Juni 2014 um 6:53 Uhr


  • Ich würde empfehlen, in der Frage noch einmal darauf hinzuweisen, dass Sie genau das meinen while(1);nicht while(1). Es ist leicht zu übersehen und verursacht Verwirrung.

    – FreeNickname

    18. Juni 2014 um 6:58 Uhr

  • meiner bescheidenen Meinung nach while (1); ist der beste Weg, um den Akku eines Laptops zu entladen …

    – Axel

    18. Juni 2014 um 9:01 Uhr

  • #define ever ;; #define loop ; for (ever) loop

    – Zaq

    19. Juni 2014 um 1:07 Uhr

Benutzeravatar von dureuill
dureuill

Bitte beachten Sie, dass alle gültigen Aussagen der Sprache nicht müssen, zu … haben einem Zweck dienen. Sie sind gemäß der Grammatik der Sprache gültig. Man kann viele ähnliche “unnütze” Aussagen bauen, wie z if (1);. Ich sehe solche Aussagen als Konjunktion eines Bedingungssatzes (if, whileusw.) und die leere Anweisung ; (was auch eine gültige Aussage ist, obwohl sie offensichtlich keinem bestimmten Zweck dient).

Davon abgesehen bin ich begegnet while (1); im Sicherheitscode. Wenn der Benutzer etwas sehr Schlechtes mit einem eingebetteten Gerät macht, kann es gut sein, ihn daran zu hindern, etwas anderes zu versuchen. Mit while (1);können wir ein Gerät bedingungslos sperren, bis ein akkreditierter Betreiber es manuell neu startet.

while(1); kann auch Teil der Implementierung einer Kernel-Panic sein, obwohl a for(;;) {} Schleife scheint eine gebräuchlichere Art zu sein, die Endlosschleife auszudrücken, und es könnte einen nicht leeren Körper geben (zum Beispiel to panic_blink()).

  • Ein weiterer Anwendungsfall für eine leere Endlosschleife ist die Implementierung assert()was Ihrem Sicherheitsbeispiel natürlich sehr ähnlich ist.

    – abschalten

    18. Juni 2014 um 7:12 Uhr

  • @DavidHammen sollen Compiler-Optimierungen nicht funktional gleichwertig bleiben?

    – svvac

    18. Juni 2014 um 11:38 Uhr

  • @DavidHammen Ich spreche von sehr spezifischen Toolchains und sehr spezifischen Compilern. Leute, die dies tun, wissen normalerweise, was sie tun, und sie schreiben keinen portablen Code.

    – dureuill

    18. Juni 2014 um 12:06 Uhr


  • @DavidHammen Soweit ich weiß, kann ein C++-Compiler diese Schleife frei optimieren, aber kein C-Compiler.

    – Kevin

    18. Juni 2014 um 14:36 ​​Uhr

  • @ user2357112 das würde eigentlich nur darum bitten, die Nische, von der es glaubt, dass es sie füllt, wirklich zu füllen. Es ist keine seltsame Funktion, die nur in hochspezialisierten Sprachen oder so etwas zu sehen ist. Es ist nur das Grundprinzip, das zu tun, was Sie geschrieben haben, und ja, ich weiß, dass C im Allgemeinen zu gut dafür ist. Es würde Ihren Code lieber als Vorschlag nehmen und dann etwas Zufälliges tun, “weil es kann”.

    – Harald

    20. Juni 2014 um 7:34 Uhr

Benutzeravatar von a.atlam
a.atlam

Wenn Sie sich mit der Assemblierung befassen (dies ist aus Sicht eingebetteter Systeme leichter zu verstehen oder wenn Sie versucht haben, einen Bootloader zu programmieren)

Sie werden feststellen, dass eine While-Schleife nur eine jmp-Anweisung ist … dh

(pseudo code: starting loop address)
add ax, bx
add ax, cx
cmp ax, dx
jz  (pseudo code: another address location)
jmp (pseudo code: starting loop address)

Lassen Sie uns erklären, wie das funktioniert. Der Prozessor führt die Anweisungen weiterhin nacheinander aus … egal was passiert. In dem Moment, in dem es in diese Schleife eintritt, fügt es also das Register bx zu ax hinzu und speichert es in ax, fügt das Register cx zu ax hinzu und speichert es zu ax, cmp ax, dx (dies bedeutet, subtrahiere dx von ax), die jz-Anweisung bedeutet, zu (einer anderen Adresse) zu springen Ort), wenn das Null-Flag gesetzt ist (was ein Bit im Flag-Register ist, das gesetzt wird, wenn das Ergebnis der obigen Subtraktion Null ist), dann jmp zur Anfangsschleifenadresse (ziemlich einfach) und das Ganze wiederholen.

Der Grund, warum ich Sie mit dieser ganzen Versammlung belästigt habe, ist, Ihnen zu zeigen, dass dies in C übersetzt werden würde

int A,B,C,D;
// initialize to what ever;

while(true)
{
A = A + B;
A = A + C;

if((A-D)==0)
{break;}

}

// if((X-Y)==0){break;} is the 
// cmp ax, dx
// jz  (pseudo code: another address location)

Stellen Sie sich also das Senario in Assembly vor, wenn Sie nur eine sehr lange Liste von Anweisungen hätten, die nicht mit einem jmp (der While-Schleife) enden, um einen Abschnitt zu wiederholen oder ein neues Programm zu laden oder etwas zu tun … Irgendwann wird der Prozessor das erreichen letzte Anweisung und laden Sie dann die folgende Anweisung, um nichts zu finden (es wird dann einfrieren oder drei Fehler oder so etwas).

Genau aus diesem Grund müssen Sie, wenn Sie möchten, dass das Programm nichts tut, bis ein Ereignis ausgelöst wird, eine While(1)-Schleife verwenden, damit der Prozessor an seine Stelle springt und diese leere Befehlsadresse nicht erreicht. Wenn das Ereignis ausgelöst wird, springt es zur Adresse der Ereignishandler-Anweisung, führt sie aus, löscht den Interrupt und kehrt zu Ihrer while(1)-Schleife zurück, die einfach an ihre Stelle springt und auf weitere Interrupts wartet. Übrigens wird while(1) als Superloop bezeichnet, wenn Sie mehr darüber lesen möchten … Nur für diejenigen, die es wahnsinnig jucken, an dieser Stelle zu argumentieren und negativ zu kommentieren, dies ist kein Assembler-Tutorial oder eine Vorlesung oder so etwas. Es ist nur eine einfache englische Erklärung, die so einfach wie möglich ist und viele zugrunde liegende Details wie Zeiger und Stapel und so weiter übersieht und manchmal Dinge vereinfacht, um einen Punkt zu vermitteln. Niemand sucht hier nach Dokumentationsgenauigkeit und ich weiß, dass dieser C-Code nicht so kompiliert wird, aber dies ist nur für die Demo !!

  • Im Klartext wird es also verwendet, um zu verhindern, dass Ihr Programm beendet wird, bis Sie bereit sind, selbst wenn Ihr Programm nichts tut. Ja?

    – jpmc26

    18. Juni 2014 um 22:55 Uhr

  • Ja, sehr gut gesagt, bis ein Ereignis oder ein Interrupt ausgelöst wird.

    – a.atlam

    19. Juni 2014 um 4:55 Uhr

Benutzeravatar von David Hammen
David Hammen

Dies ist mit C gekennzeichnet, aber ich beginne mit einer C++-Perspektive. In C++11 kann der Compiler frei optimiert werden while(1); ein Weg.

Aus dem C++11-Standardentwurf n3092, Abschnitt 6.5, Absatz 5 (Hervorhebung von mir):

Eine Schleife, die außerhalb der for-init-Anweisung bei einer for-Anweisung
— ruft keine Bibliotheks-E/A-Funktionen auf, und
— nicht auf flüchtige Objekte zugreift oder diese ändert, und
— führt keine Synchronisationsoperationen (1.10) oder atomare Operationen (Klausel 29) durch
kann davon ausgegangen werden, dass die Implementierung beendet wird. [Note: This is intended to allow compiler transformations, such as removal of empty loops, even when termination cannot be proven. — end note ]

Der C11-Standard hat einen ähnlichen Eintrag, jedoch mit einem wesentlichen Unterschied. Aus dem C11-Standardentwurf n1570 (Hervorhebung von mir):

Eine Iterationsanweisung dessen steuernder Ausdruck kein konstanter Ausdruck ist,156) das keine Ein-/Ausgabeoperationen ausführt, nicht auf flüchtige Objekte zugreift und keine Synchronisation oder atomaren Operationen in seinem Körper durchführt, den Ausdruck steuert, oder (im Fall einer for-Anweisung) in seinem Ausdruck-3kann von der Implementierung als beendet angenommen werden.157)

156) Ein ausgelassener Steuerausdruck wird durch eine Konstante ungleich Null ersetzt, die ein konstanter Ausdruck ist.
157) Dies soll Compiler-Transformationen wie das Entfernen von Leerschleifen auch dann ermöglichen, wenn der Abbruch nicht nachgewiesen werden kann.

Das heisst while(1); kann davon ausgegangen werden, dass sie in C++11 terminiert, aber nicht in C11. Trotzdem wird Hinweis 157 (nicht bindend) von einigen Anbietern so interpretiert, dass es ihnen erlaubt, diese leere Schleife zu entfernen. Der Unterschied zwischen while(1); in C++11 und C11 ist das von definiertem versus undefiniertem Verhalten. Da die Schleife leer ist, kann sie in C++11 gelöscht werden. In C11, while(1); ist nachweislich nicht terminierend, und das ist undefiniertes Verhalten. Da der Programmierer UB aufgerufen hat, kann der Compiler alles tun, einschließlich des Löschens dieser störenden Schleife.

Es gab eine Reihe von Stackoverflow-Diskussionen zur Optimierung des Löschens von Compilern while(1);. Zum Beispiel, Dürfen Compiler Endlosschleifen eliminieren?, Wird eine leere For-Schleife, die als Ruhezustand verwendet wird, wegoptimiert?, Wegoptimieren eines “while(1);” in C++0x. Beachten Sie, dass die ersten beiden C-spezifisch waren.

  • Gibt es überhaupt Compiler, die das können?

    Benutzer267885

    18. Juni 2014 um 14:15 Uhr

  • Einverstanden while (1); ist nicht terminierend, aber warum sollte jemand das “undefiniertes Verhalten” nennen? Es scheint mir gut definiert zu sein. Es kann sein oder auch nicht wünschenswert Verhalten, aber für einen Compiler, es wegzuoptimieren, verändert die Bedeutung des Programms und ist daher schlecht.

    – Phil Perry

    18. Juni 2014 um 14:15 Uhr

  • @Tibor: Intel, Clang und andere machen genau das. Diese zusätzliche Klausel im C11-Standard (“deren kontrollierender Ausdruck kein konstanter Ausdruck ist”) scheint dies zuzulassen while(1);. Der C11-Standard 5.1.2.3 p 4 sagt jedoch: „In der abstrakten Maschine werden alle Ausdrücke so ausgewertet, wie es die Semantik vorgibt. Eine tatsächliche Implementierung muss einen Teil eines Ausdrucks nicht auswerten, wenn daraus abgeleitet werden kann, dass sein Wert nicht verwendet wird und dass keine erforderlichen Nebeneffekte erzeugt werden …” Es gibt also noch ein Out in C11 für Compiler-Anbieter zur Optimierung while(1); ein Weg.

    – David Hamm

    18. Juni 2014 um 16:03 Uhr


  • @DavidHammen “Eine tatsächliche Implementierung muss einen Teil eines Ausdrucks nicht auswerten, wenn daraus abgeleitet werden kann, dass sein Wert nicht verwendet wird und dass keine erforderlichen Nebenwirkungen erzeugt werden.” while (1); ist eine Aussage, kein Ausdruck.

    – au

    18. Juni 2014 um 18:31 Uhr

  • Außerdem würde ich argumentieren, dass es eine hat sehr vorhersehbar Nebeneffekt. Die Beurteilung von “benötigt” ist etwas unscharfer.

    – Michael

    18. Juni 2014 um 20:51 Uhr

Benutzeravatar von ouah
ouah

Eine Verwendung für eingebettete Software besteht darin, einen Software-Reset mit dem Watchdog zu implementieren:

while (1);

oder gleichwertig, aber sicherer, da es die Absicht klarer macht:

do { /* nothing, let's the dog bite */ } while (1);

Wenn der Watchdog aktiviert ist und nach x Millisekunden nicht bestätigt wird, wissen wir, dass er den Prozessor zurücksetzen wird, also verwenden Sie dies, um einen Software-Reset zu implementieren.

Benutzeravatar von Mahonri Moriancumer
Mahonri Moriancumer

Ich gehe davon aus, dass die while(1); ist nicht verbunden mit a do Schleife…

Die einzige halbwegs nützliche Implementierung von while(1); Ich habe gesehen, dass es sich um eine Do-Nothing-Schleife handelt, die auf einen Interrupt wartet. wie ein übergeordneter Prozess, der auf ein SIGCHLD wartet, was anzeigt, dass ein untergeordneter Prozess beendet wurde. Der SIGCHLD-Handler des Elternteils kann, nachdem alle Kindprozesse beendet wurden, den Elternthread beenden.

Es macht den Trick, verschwendet aber viel CPU-Zeit. Eine solche Verwendung sollte vielleicht eine Art Ruhezustand durchführen, um den Prozessor regelmäßig freizugeben.

  • Du könntest benutzen while(1) pause(); und das ist so ziemlich das einzige, was die pause Systemaufruf ist gut für. In jedem anderen Zusammenhang mit pause ist wahrscheinlich ein Fehler, der mit behoben werden könnte sigsuspend mit richtigen Parametern.

    – Kasperd

    18. Juni 2014 um 21:35 Uhr

Benutzeravatar von waldol1
waldol1

Ein Ort, den ich gesehen habe while(1); liegt in der eingebetteten Programmierung.

Die Architektur verwendete einen Hauptthread, um Ereignisse zu überwachen, und Worker-Threads, um sie zu verarbeiten. Es gab einen Hardware-Watchdog-Timer (Erklärung hier), die nach einiger Zeit einen Soft-Reset des Moduls durchführen würden. Innerhalb der Polling-Schleife des Haupt-Threads würde es diesen Timer zurücksetzen. Wenn der Haupt-Thread einen nicht behebbaren Fehler erkannt hat, a while(1); würde verwendet werden, um den Haupt-Thread zu binden und so den Watchdog-Reset auszulösen. Ich glaube, dass Assert Failure mit a implementiert wurde while(1); auch.

  • Du könntest benutzen while(1) pause(); und das ist so ziemlich das einzige, was die pause Systemaufruf ist gut für. In jedem anderen Zusammenhang mit pause ist wahrscheinlich ein Fehler, der mit behoben werden könnte sigsuspend mit richtigen Parametern.

    – Kasperd

    18. Juni 2014 um 21:35 Uhr

Wie andere gesagt haben, ist es nur eine Endlosschleife, die nichts tut, ganz analog zu

while (1) {
    /* Do nothing */
}

Die Schleife mit dem Semikolon hat einen Körper. Wenn es als Anweisung verwendet wird, ist ein einzelnes Semikolon a Null-Aussageund der Schleifenkörper besteht aus dieser Nullanweisung.

Aus Gründen der Lesbarkeit und um dem Leser klar zu machen, dass die null-Anweisung der Hauptteil der Schleife ist, empfehle ich, sie in eine separate Zeile zu schreiben:

while (1)
    ;

Andernfalls ist es leicht, es am Ende der „while“-Zeile zu übersehen, wo normalerweise kein Semikolon steht, und der Leser kann die nächste Zeile fälschlicherweise für den Rumpf der Schleife halten.

Oder verwenden Sie stattdessen eine leere zusammengesetzte Anweisung.

1412060cookie-checkZweck von while(1); Aussage in C

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

Privacy policy