Warum ist volatile
in C benötigt? Wofür wird es verwendet? Was wird es tun?
Antworten
Zu viele Anzeigen?Meine einfache Erklärung ist:
In einigen Szenarien optimiert der Compiler auf der Grundlage der Logik oder des Codes die Variablen, von denen er annimmt, dass sie sich nicht ändern. Die volatile
Schlü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 könnte der Compiler denken usb_interface_flag
als 0 definiert ist und in der while-Schleife für immer Null sein wird. Nach der Optimierung behandelt der Compiler sie als while(true)
ständig, was zu einer Endlosschleife führt.
Um diese Art von Szenarien zu vermeiden, deklarieren wir das Flag als flüchtig. Damit teilen wir dem Compiler mit, dass dieser Wert von einer externen Schnittstelle oder einem anderen Programmmodul geändert werden kann, d.h. bitte nicht optimieren. Das ist der Anwendungsfall für volatile.
Eine marginale Verwendung für flüchtige Stoffe ist die folgende. Angenommen, Sie wollen 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 x+h-x
ist im Allgemeinen nicht gleich h
aufgrund von Rundungsfehlern. Denken Sie darüber nach: Wenn Sie sehr nahe beieinander liegende Zahlen subtrahieren, verlieren Sie viele signifikante Ziffern, was die Berechnung der Ableitung ruinieren kann (denken Sie an 1,00001 - 1). Eine mögliche Abhilfe 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;
}
aber je nach Plattform und Compiler-Switches kann die zweite Zeile dieser Funktion durch einen aggressiv optimierenden Compiler ausgelöscht werden. Sie schreiben also stattdessen
volatile double hh = x + h;
hh -= x;
um den Compiler zu zwingen, den Speicherplatz zu lesen, der hh enthält, und damit eine eventuelle Optimierungsmöglichkeit zu verpassen.
Es gibt zwei Verwendungszwecke. Diese werden speziell in der Embedded-Entwicklung häufiger verwendet.
-
Der Compiler optimiert nicht die Funktionen, die Variablen verwenden, die mit dem Schlüsselwort volatile definiert sind
-
Flüchtig wird verwendet, um auf genaue Speicherplätze im RAM, ROM usw. zuzugreifen. Dies wird häufiger verwendet, um Geräte mit Speicherzuordnung zu steuern, auf CPU-Register zuzugreifen und bestimmte Speicherplätze zu finden.
Siehe Beispiele in der Baugruppenliste. Re: Verwendung des C-Schlüsselworts "volatile" in der Embedded-Entwicklung
Ich möchte noch ein weiteres Szenario erwähnen, bei dem flüchtige Stoffe eine Rolle spielen.
Angenommen, Sie ordnen eine Datei dem Speicher zu, um die E/A zu beschleunigen, und diese Datei kann sich im Hintergrund ä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 Memory-Mapped-Datei zugreifen, kann der vom Compiler erzeugte Code dieselben Daten mehrfach abrufen, ohne dass Sie dies bemerken.
Wenn sich diese Daten ändern, kann es passieren, dass Ihr Programm zwei oder mehr verschiedene Versionen der Daten verwendet und in einen inkonsistenten Zustand gerät. Dies kann nicht nur zu einem logisch falschen Verhalten des Programms führen, sondern auch zu ausnutzbaren Sicherheitslücken, wenn es nicht vertrauenswürdige Dateien oder Dateien von nicht vertrauenswürdigen Orten verarbeitet.
Wenn Ihnen die Sicherheit am Herzen liegt, und das sollten Sie, ist dies ein wichtiges Szenario, das Sie berücksichtigen sollten.