Warum wird in C flüchtig benötigt?


Antworten:


423

Volatile weist den Compiler an, nichts zu optimieren, was mit der flüchtigen Variablen zu tun hat.

Es gibt mindestens drei häufige Gründe für die Verwendung: In allen Situationen kann sich der Wert der Variablen ändern, ohne dass der sichtbare Code eine Aktion ausführt: Wenn Sie eine Schnittstelle zu Hardware herstellen, die den Wert selbst ändert; wenn ein anderer Thread ausgeführt wird, der ebenfalls die Variable verwendet; oder wenn es einen Signalhandler gibt, der den Wert der Variablen ändern kann.

Angenommen, Sie haben ein kleines Stück Hardware, das irgendwo im RAM abgebildet ist und zwei Adressen hat: einen Befehlsport und einen Datenport:

typedef struct
{
  int command;
  int data;
  int isbusy;
} MyHardwareGadget;

Jetzt möchten Sie einen Befehl senden:

void SendCommand (MyHardwareGadget * gadget, int command, int data)
{
  // wait while the gadget is busy:
  while (gadget->isbusy)
  {
    // do nothing here.
  }
  // set data first:
  gadget->data    = data;
  // writing the command starts the action:
  gadget->command = command;
}

Sieht einfach aus, kann aber fehlschlagen, da der Compiler die Reihenfolge ändern kann, in der Daten und Befehle geschrieben werden. Dies würde dazu führen, dass unser kleines Gadget Befehle mit dem vorherigen Datenwert ausgibt. Schauen Sie sich auch die Wartezeit während der Besetztschleife an. Dieser wird optimiert. Der Compiler wird versuchen, klug zu sein, den Wert von isbusy nur einmal zu lesen und dann in eine Endlosschleife zu gehen. Das willst du nicht.

Um dies zu umgehen, müssen Sie das Zeiger-Gadget als flüchtig deklarieren. Auf diese Weise ist der Compiler gezwungen, das zu tun, was Sie geschrieben haben. Es kann die Speicherzuweisungen nicht entfernen, es kann keine Variablen in Registern zwischenspeichern und es kann auch die Reihenfolge der Zuweisungen nicht ändern:

Dies ist die richtige Version:

   void SendCommand (volatile MyHardwareGadget * gadget, int command, int data)
    {
      // wait while the gadget is busy:
      while (gadget->isbusy)
      {
        // do nothing here.
      }
      // set data first:
      gadget->data    = data;
      // writing the command starts the action:
      gadget->command = command;
    }

46
Persönlich würde ich es vorziehen, wenn die Ganzzahl explizit ist, z. B. int8 / int16 / int32, wenn mit Hardware gesprochen wird. Schöne Antwort aber;)
Tonylo

22
Ja, Sie sollten Dinge mit einer festen Registergröße deklarieren, aber hey - es ist nur ein Beispiel.
Nils Pipenbrinck

69
Volatile wird auch in Thread-Code benötigt, wenn Sie mit Daten spielen, die nicht durch Parallelität geschützt sind. Und ja, es gibt gültige Zeiten dafür. Sie können beispielsweise eine thread-sichere zirkuläre Nachrichtenwarteschlange schreiben, ohne einen expliziten Parallelitätsschutz zu benötigen, aber es werden flüchtige Stoffe benötigt.
Gordon Wrigley

14
Lesen Sie die C-Spezifikation genauer durch. Volatile hat nur ein definiertes Verhalten für speicherabgebildete Geräte-E / A oder Speicher, die von einer asynchronen Unterbrechungsfunktion berührt werden. Es sagt nichts über Threading aus, und ein Compiler, der den Zugriff auf Speicher optimiert, der von mehreren Threads berührt wird, ist konform.
Ephemient

17
@ Tolomea: völlig falsch. traurige 17 Personen wissen es nicht. flüchtig ist kein Gedächtniszaun. Es bezieht sich nur auf die Vermeidung der Code-Elision während der Optimierung unter der Annahme nicht sichtbarer Nebenwirkungen .
v.oddou

187

volatilein C entstand tatsächlich, um die Werte der Variablen nicht automatisch zwischenzuspeichern. Der Compiler wird angewiesen, den Wert dieser Variablen nicht zwischenzuspeichern. Es wird also Code generiert, der bei volatilejeder Begegnung den Wert der angegebenen Variablen aus dem Hauptspeicher entnimmt. Dieser Mechanismus wird verwendet, da der Wert jederzeit vom Betriebssystem oder einem Interrupt geändert werden kann. Die Verwendung volatilehilft uns also, jedes Mal neu auf den Wert zuzugreifen.


Entstanden? Wurde "flüchtig" nicht ursprünglich aus C ++ ausgeliehen? Nun, ich scheine mich zu erinnern ...
Syntaxfehler

Dies ist nicht alles flüchtig - es verbietet auch einige Nachbestellungen, wenn als flüchtig angegeben ..
FaceBro

4
@FaceBro: Der Zweck von volatilewar es, Compilern die Optimierung von Code zu ermöglichen und gleichzeitig Programmierern die Möglichkeit zu geben, die Semantik zu erreichen, die ohne solche Optimierungen erreicht werden würde. Die Autoren des Standards erwarteten, dass Qualitätsimplementierungen jede Semantik unterstützen würden, die angesichts ihrer Zielplattformen und Anwendungsfelder nützlich ist, und erwarteten nicht, dass Compiler-Autoren versuchen würden, die Semantik mit der niedrigsten Qualität anzubieten, die dem Standard entspricht und nicht 100% ist dumm (beachten Sie, dass die Autoren des Standards ausdrücklich in der Begründung anerkennen ...
Supercat

1
... dass es möglich ist, dass eine Implementierung konform ist, ohne von ausreichender Qualität zu sein, um tatsächlich für irgendeinen Zweck geeignet zu sein, aber sie hielten es nicht für notwendig, dies zu verhindern).
Supercat

1
@syntaxerror Wie kann es aus C ++ ausgeliehen werden, wenn C mehr als ein Jahrzehnt älter als C ++ war (sowohl bei Erstversionen als auch bei Erststandards)?
Phuclv

178

Eine andere Verwendung für volatileist Signalhandler. Wenn Sie folgenden Code haben:

int quit = 0;
while (!quit)
{
    /* very small loop which is completely visible to the compiler */
}

Der Compiler darf feststellen, dass der Schleifenkörper die quitVariable nicht berührt , und die Schleife in eine while (true)Schleife konvertieren . Auch wenn die quitVariable im Signalhandler für SIGINTund gesetzt ist SIGTERM; Der Compiler kann das nicht wissen.

Wenn die quitVariable jedoch deklariert ist volatile, muss der Compiler sie jedes Mal laden, da sie an anderer Stelle geändert werden kann. Dies ist genau das, was Sie in dieser Situation wollen.


Wenn Sie sagen "Der Compiler muss es jedes Mal laden, ist es so, als würde der Compiler eine bestimmte Variable optimieren und wir deklarieren die Variable nicht als flüchtig. Zur Laufzeit wird diese bestimmte Variable in CPU-Register geladen, die sich nicht im Speicher befinden." ?
Amit Singh Tomar

1
@AmitSinghTomar Es bedeutet, was es sagt: Jedes Mal, wenn der Code den Wert überprüft, wird er neu geladen. Andernfalls kann der Compiler davon ausgehen, dass Funktionen, die keinen Verweis auf die Variable enthalten, diese nicht ändern können. Unter der Annahme, dass CesarB beabsichtigt, dass die obige Schleife nicht festgelegt wird quit, kann der Compiler sie unter der Annahme in eine konstante Schleife optimieren dass es keine Möglichkeit gibt, quitzwischen Iterationen geändert zu werden. NB: Dies ist nicht unbedingt ein guter Ersatz für die eigentliche threadsichere Programmierung.
underscore_d

Wenn quit eine globale Variable ist, soll der Compiler die while-Schleife nicht optimieren, richtig?
Pierre G.

2
@PierreG. Nein, der Compiler kann immer davon ausgehen, dass der Code Single-Threaded ist, sofern nicht anders angegeben. Das heißt, volatilewenn keine oder andere Markierungen vorhanden sind, wird davon ausgegangen, dass nichts außerhalb der Schleife diese Variable ändert, sobald sie in die Schleife eintritt, selbst wenn es sich um eine globale Variable handelt.
CesarB

1
@PierreG. Ja, versuchen Sie beispielsweise, extern int global; void fn(void) { while (global != 0) { } }mit gcc -O3 -Sder resultierenden Assembly-Datei zu kompilieren und sie anzusehen. Auf meinem Computer ist dies der Fall movl global(%rip), %eax. testl %eax, %eax;; je .L1;; .L4: jmp .L4Das heißt, eine Endlosschleife, wenn die globale nicht Null ist. Versuchen Sie dann hinzuzufügen volatileund sehen Sie den Unterschied.
CesarB

60

volatileteilt dem Compiler mit, dass Ihre Variable auf andere Weise geändert werden kann als durch den Code, der darauf zugreift. Beispielsweise kann es sich um einen E / A-zugeordneten Speicherort handeln. Wenn dies in solchen Fällen nicht angegeben ist, können einige variable Zugriffe optimiert werden, z. B. kann der Inhalt in einem Register gespeichert werden und der Speicherort wird nicht erneut eingelesen.


30

Siehe diesen Artikel von Andrei Alexandrescu, " volatile - Multithreaded Programmer's Best Friend "

Das flüchtige Schlüsselwort wurde entwickelt, um Compileroptimierungen zu verhindern, die bei bestimmten asynchronen Ereignissen zu falschem Code führen können. Wenn Sie beispielsweise eine primitive Variable als flüchtig deklarieren , darf der Compiler sie nicht in einem Register zwischenspeichern - eine häufige Optimierung, die katastrophal wäre, wenn diese Variable von mehreren Threads gemeinsam genutzt würde. Die allgemeine Regel lautet also: Wenn Sie Variablen vom primitiven Typ haben, die von mehreren Threads gemeinsam genutzt werden müssen, deklarieren Sie diese Variablen als flüchtig. Mit diesem Schlüsselwort können Sie jedoch noch viel mehr tun: Sie können damit Code abfangen, der nicht threadsicher ist, und dies zum Zeitpunkt der Kompilierung. Dieser Artikel zeigt, wie es gemacht wird; Die Lösung beinhaltet einen einfachen intelligenten Zeiger, der es auch einfach macht, kritische Codeabschnitte zu serialisieren.

Der Artikel gilt sowohl für Cals auch C++.

Siehe auch den Artikel " C ++ und die Gefahren des Double-Checked Locking " von Scott Meyers und Andrei Alexandrescu:

Wenn Sie sich also mit einigen Speicherorten befassen (z. B. Speicherzuordnungsports oder Speicher, auf den ISRs [Interrupt Service Routines] verweisen), müssen einige Optimierungen ausgesetzt werden. flüchtig gibt es, um eine spezielle Behandlung für solche Orte festzulegen, insbesondere: (1) der Inhalt einer flüchtigen Variablen ist "instabil" (kann sich durch dem Compiler unbekannte Mittel ändern), (2) alle Schreibvorgänge in flüchtige Daten sind "beobachtbar", so dass sie muss religiös ausgeführt werden, und (3) alle Operationen an flüchtigen Daten werden in der Reihenfolge ausgeführt, in der sie im Quellcode erscheinen. Die ersten beiden Regeln gewährleisten das richtige Lesen und Schreiben. Das letzte ermöglicht die Implementierung von E / A-Protokollen, die Eingabe und Ausgabe mischen. Dies ist informell, was die volatilen Garantien von C und C ++ garantieren.


Gibt der Standard an, ob ein Lesevorgang als "beobachtbares Verhalten" betrachtet wird, wenn der Wert nie verwendet wird? Mein Eindruck ist, dass es sein sollte, aber als ich behauptete, es sei woanders, forderte mich jemand zu einem Zitat auf. Es scheint mir, dass auf jeder Plattform, auf der das Lesen einer flüchtigen Variablen möglicherweise Auswirkungen haben könnte, ein Compiler aufgefordert werden sollte, Code zu generieren, der jeden angegebenen Lesevorgang genau einmal ausführt. Ohne diese Anforderung wäre es schwierig, Code zu schreiben, der eine vorhersagbare Folge von Lesevorgängen erzeugt.
Supercat

@supercat: Laut dem ersten Artikel "Wenn Sie den flüchtigen Modifikator für eine Variable verwenden, wird diese Variable vom Compiler nicht in Registern zwischengespeichert - jeder Zugriff trifft den tatsächlichen Speicherort dieser Variablen." In Abschnitt §6.7.3.6 des c99-Standards heißt es außerdem: "Ein Objekt mit einem flüchtig qualifizierten Typ kann auf für die Implementierung unbekannte Weise geändert werden oder andere unbekannte Nebenwirkungen haben." Dies impliziert ferner, dass flüchtige Variablen möglicherweise nicht in Registern zwischengespeichert werden und dass alle Lese- und Schreibvorgänge in der Reihenfolge relativ zu Sequenzpunkten ausgeführt werden müssen, damit sie tatsächlich beobachtbar sind.
Robert S. Barnes

Der letztere Artikel besagt in der Tat ausdrücklich, dass Lesevorgänge Nebenwirkungen sind. Ersteres weist darauf hin, dass Lesevorgänge nicht außerhalb der Reihenfolge ausgeführt werden können, aber die Möglichkeit einer vollständigen Eliminierung nicht auszuschließen schienen.
Supercat

„Der Compiler ist nicht erlaubt es in einem Register cachen“ - Die meisten RISC arcitectures ae Register-Maschinen, so dass jeder RMW-Befehl hat das Objekt in einem Register zwischenzuspeichern. volatilegarantiert keine Atomizität.
zu ehrlich für diese Seite

1
@Olaf: Etwas in ein Register zu laden ist nicht dasselbe wie Caching. Das Zwischenspeichern würde die Anzahl der Ladungen oder Speicher oder deren Zeitpunkt beeinflussen.
Supercat

28

Meine einfache Erklärung lautet:

In einigen Szenarien optimiert der Compiler basierend auf der Logik oder dem Code Variablen, von denen er glaubt, dass sie sich nicht ändern. Das volatileSchlüsselwort verhindert, dass eine Variable optimiert wird.

Zum Beispiel:

bool usb_interface_flag = 0;
while(usb_interface_flag == 0)
{
    // execute logic for the scenario where the USB isn't connected 
}

Aus dem obigen Code geht der Compiler möglicherweise davon aus, dass er usb_interface_flagals 0 definiert ist und dass er in der while-Schleife für immer Null ist. Nach der Optimierung wird es vom Compiler wie immer behandelt while(true), was zu einer Endlosschleife führt.

Um diese Art von Szenarien zu vermeiden, deklarieren wir das Flag als flüchtig. Wir teilen dem Compiler mit, dass dieser Wert durch eine externe Schnittstelle oder ein anderes Programmmodul geändert werden kann, dh bitte nicht optimieren. Das ist der Anwendungsfall für volatile.


19

Eine marginale Verwendung für flüchtige Stoffe ist die folgende. Angenommen, Sie möchten die numerische Ableitung einer Funktion berechnen f:

double der_f(double x)
{
    static const double h = 1e-3;
    return (f(x + h) - f(x)) / h;
}

Das Problem ist, dass aufgrund von Rundungsfehlern im x+h-xAllgemeinen nicht gleich hist. Denken Sie darüber nach: Wenn Sie sehr nahe Zahlen subtrahieren, verlieren Sie viele signifikante Ziffern, die die Berechnung der Ableitung ruinieren können (denken Sie an 1.00001 - 1). Eine mögliche Problemumgehung könnte sein

double der_f2(double x)
{
    static const double h = 1e-3;
    double hh = x + h - x;
    return (f(x + hh) - f(x)) / hh;
}

Abhängig von Ihrer Plattform und den Compiler-Switches kann die zweite Zeile dieser Funktion von einem aggressiv optimierenden Compiler gelöscht werden. Also schreibst du stattdessen

    volatile double hh = x + h;
    hh -= x;

um den Compiler zu zwingen, den Speicherort zu lesen, der hh enthält, verfällt eine mögliche Optimierungsmöglichkeit.


Was ist ein Unterschied zwischen der Verwendung hoder der hhabgeleiteten Formel? Wenn hhberechnet wird, verwendet die letzte Formel sie wie die erste, ohne Unterschied. Vielleicht sollte es sein (f(x+h) - f(x))/hh?
Sergey Zhukov

2
Der Unterschied zwischen hund hhbesteht darin, dass hhdurch die Operation eine negative Zweierpotenz abgeschnitten wird x + h - x. In diesem Fall x + hhund xunterscheiden sich genau um hh. Sie können auch Ihre Formel nehmen, sie ergibt das gleiche Ergebnis, da x + hund x + hhgleich sind (es ist der Nenner, der hier wichtig ist).
Alexandre C.

3
Ist es nicht lesbarer, dies zu schreiben x1=x+h; d = (f(x1)-f(x))/(x1-x)? ohne das flüchtige zu verwenden.
Sergey Zhukov

Gibt es einen Hinweis, dass ein Compiler diese zweite Zeile der Funktion löschen kann?
CoffeeTableEspresso

@ CoffeeTableEspresso: Nein, sorry. Je mehr ich über Gleitkomma weiß, desto mehr glaube ich, dass der Compiler es nur optimieren darf, wenn dies explizit mit -ffast-mathoder gleichwertig angegeben wird.
Alexandre C.

11

Es gibt zwei Verwendungszwecke. Diese werden besonders häufig in der Embedded-Entwicklung eingesetzt.

  1. Der Compiler optimiert nicht die Funktionen, die Variablen verwenden, die mit dem Schlüsselwort volatile definiert sind

  2. Volatile wird verwendet, um auf genaue Speicherorte im RAM, ROM usw. zuzugreifen. Dies wird häufiger verwendet, um speicherabgebildete Geräte zu steuern, auf CPU-Register zuzugreifen und bestimmte Speicherorte zu lokalisieren.

Siehe Beispiele mit Baugruppenliste. Betreff: Verwendung des Schlüsselworts "volatile" C in der eingebetteten Entwicklung


"Der Compiler optimiert nicht die Funktionen, die Variablen verwenden, die mit dem Schlüsselwort volatile definiert sind" - das ist einfach falsch.
zu ehrlich für diese Seite

10

Volatile ist auch nützlich, wenn Sie den Compiler zwingen möchten, eine bestimmte Codesequenz nicht zu optimieren (z. B. zum Schreiben eines Mikro-Benchmarks).


10

Ich werde ein anderes Szenario erwähnen, in dem flüchtige Stoffe wichtig sind.

Angenommen, Sie ordnen eine Datei für eine schnellere E / A zu und diese Datei kann sich hinter den Kulissen ändern (z. B. befindet sich die Datei nicht auf Ihrer lokalen Festplatte, sondern wird stattdessen von einem anderen Computer über das Netzwerk bereitgestellt).

Wenn Sie über Zeiger auf nichtflüchtige Objekte (auf Quellcodeebene) auf die Daten der Speicherzuordnungsdatei zugreifen, kann der vom Compiler generierte Code dieselben Daten mehrmals abrufen, ohne dass Sie sich dessen bewusst sind.

Wenn sich diese Daten ändern, verwendet Ihr Programm möglicherweise zwei oder mehr verschiedene Versionen der Daten und gerät in einen inkonsistenten Zustand. Dies kann nicht nur zu einem logisch inkorrekten Verhalten des Programms führen, sondern auch zu ausnutzbaren Sicherheitslücken, wenn es nicht vertrauenswürdige Dateien oder Dateien von nicht vertrauenswürdigen Speicherorten verarbeitet.

Wenn Sie Wert auf Sicherheit legen und dies sollten, ist dies ein wichtiges Szenario.


7

flüchtig bedeutet, dass sich der Speicher wahrscheinlich jederzeit ändert und geändert wird, jedoch außerhalb der Kontrolle des Benutzerprogramms. Dies bedeutet, dass das Programm, wenn Sie auf die Variable verweisen, immer die physikalische Adresse (dh eine zugeordnete Eingabe-Fifo) überprüfen und nicht zwischengespeichert verwenden sollte.


Kein Compiler bedeutet "flüchtig" entweder "physikalische Adresse im RAM" oder "den Cache umgehen".
Neugieriger


5

Meiner Meinung nach sollte man nicht zu viel erwarten volatile. Schauen Sie sich zur Veranschaulichung das Beispiel in Nils Pipenbrincks hochgewählter Antwort an .

Ich würde sagen, sein Beispiel ist nicht geeignet für volatile. volatilewird nur verwendet, um: den Compiler daran zu hindern, nützliche und wünschenswerte Optimierungen vorzunehmen . Es geht nicht um den Thread-sicheren, atomaren Zugriff oder sogar die Speicherreihenfolge.

In diesem Beispiel:

    void SendCommand (volatile MyHardwareGadget * gadget, int command, int data)
    {
      // wait while the gadget is busy:
      while (gadget->isbusy)
      {
        // do nothing here.
      }
      // set data first:
      gadget->data    = data;
      // writing the command starts the action:
      gadget->command = command;
    }

Das gadget->data = dataVorherige gadget->command = commandwird nur im kompilierten Code vom Compiler garantiert. Zur Laufzeit ordnet der Prozessor möglicherweise noch die Daten- und Befehlszuweisung in Bezug auf die Prozessorarchitektur neu an. Die Hardware könnte die falschen Daten erhalten (angenommen, das Gadget ist der Hardware-E / A zugeordnet). Die Speicherbarriere wird zwischen Daten- und Befehlszuweisung benötigt.


2
Ich würde sagen, dass flüchtig verwendet wird, um zu verhindern, dass der Compiler Optimierungen vornimmt, die normalerweise nützlich und wünschenswert wären . Wie geschrieben, klingt es so, volatileals würde die Leistung ohne Grund beeinträchtigt. Ob dies ausreicht, hängt von anderen Aspekten des Systems ab, über die der Programmierer möglicherweise mehr weiß als der Compiler. Wenn andererseits ein Prozessor garantiert, dass eine Anweisung zum Schreiben an eine bestimmte Adresse den CPU-Cache leert, ein Compiler jedoch keine Möglichkeit bietet, registrierungsgespeicherte Variablen zu leeren, von denen die CPU nichts weiß, wäre das Leeren des Caches nutzlos.
Supercat

5

In der von Dennis Ritchie entworfenen Sprache verhält sich jeder Zugriff auf ein Objekt außer automatischen Objekten, deren Adresse nicht vergeben wurde, so, als würde er die Adresse des Objekts berechnen und dann den Speicher an dieser Adresse lesen oder schreiben. Dies machte die Sprache sehr leistungsfähig, aber die Optimierungsmöglichkeiten stark eingeschränkt.

Während es möglich gewesen wäre, ein Qualifikationsmerkmal hinzuzufügen, das einen Compiler auffordert, anzunehmen, dass ein bestimmtes Objekt nicht auf seltsame Weise geändert wird, wäre eine solche Annahme für die überwiegende Mehrheit der Objekte in C-Programmen angemessen, und dies wäre der Fall Es war unpraktisch, allen Objekten, für die eine solche Annahme angemessen wäre, ein Qualifikationsmerkmal hinzuzufügen. Andererseits müssen einige Programme einige Objekte verwenden, für die eine solche Annahme nicht gelten würde. Um dieses Problem zu beheben, geht der Standard davon aus, dass Compiler davon ausgehen können, dass bei Objekten, die nicht deklariert volatilesind, ihr Wert nicht auf eine Weise beobachtet oder geändert wird, die außerhalb der Kontrolle des Compilers liegt oder außerhalb des Verständnisses eines vernünftigen Compilers liegt.

Da verschiedene Plattformen unterschiedliche Möglichkeiten haben, Objekte außerhalb der Kontrolle eines Compilers zu beobachten oder zu ändern, sollten sich Qualitätscompiler für diese Plattformen in ihrer genauen Handhabung der volatileSemantik unterscheiden. Da der Standard nicht vorschlug, dass Qualitätscompiler, die für die Programmierung auf niedriger Ebene auf einer Plattform vorgesehen sind, so behandelt werden sollten volatile, dass alle relevanten Auswirkungen eines bestimmten Lese- / Schreibvorgangs auf dieser Plattform erkannt werden, sind viele Compiler leider nicht in der Lage, dies zu tun Auf eine Weise, die es schwieriger macht, Dinge wie Hintergrund-E / A auf eine Weise zu verarbeiten, die effizient ist, aber nicht durch Compiler- "Optimierungen" unterbrochen werden kann.


5

In einfachen Worten, es weist den Compiler an, keine Optimierung für eine bestimmte Variable vorzunehmen. Variablen, die dem Geräteregister zugeordnet sind, werden vom Gerät indirekt geändert. In diesem Fall muss flüchtig verwendet werden.


1
Gibt es etwas Neues in dieser Antwort, das zuvor nicht erwähnt wurde?
Slfan

3

Ein flüchtiger Bestandteil kann von außerhalb des kompilierten Codes geändert werden (z. B. kann ein Programm eine flüchtige Variable einem Speicherabbildungsregister zuordnen.) Der Compiler wendet bestimmte Optimierungen nicht auf Code an, der eine flüchtige Variable verarbeitet - zum Beispiel hat er gewonnen. t Laden Sie es in ein Register, ohne es in den Speicher zu schreiben. Dies ist wichtig beim Umgang mit Hardwareregistern.


0

Wie von vielen hier zu Recht vorgeschlagen, besteht die beliebte Verwendung des flüchtigen Schlüsselworts darin, die Optimierung der flüchtigen Variablen zu überspringen.

Der beste Vorteil , dass in den Sinn kommt, und erwähnenswert , nach etwa flüchtigen Lesen ist - zu verhindern ein Zurückrollen der Variablen im Falle eines longjmp. Ein nicht lokaler Sprung.

Was bedeutet das?

Dies bedeutet einfach, dass der letzte Wert nach dem Abwickeln des Stapels beibehalten wird, um zu einem vorherigen Stapelrahmen zurückzukehren. in der Regel im Falle eines fehlerhaften Szenarios.

Da dies nicht in den Rahmen dieser Frage fällt, gehe ich hier nicht auf Details setjmp/longjmpein, aber es lohnt sich, darüber zu lesen. und wie die Volatilitätsfunktion verwendet werden kann, um den letzten Wert beizubehalten.


-2

Der Compiler kann die Werte von Variablen nicht automatisch ändern. Eine flüchtige Variable dient der dynamischen Verwendung.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.