Betrachten Sie Folgendes:
%Vor%Woher weiß ich, ob gcc mich als volatil behandelt hat oder nicht? Es würde als solches deklariert werden, da kein nahegelegener Code es modifizieren wird, und eine Modifikation davon wahrscheinlich auf einen Interrupt zurückzuführen ist.
Ich bin nicht der schlechteste Programmierer der Welt, aber ich spiele einen im Fernsehen. Kann mir jemand helfen zu verstehen, wie es anders wäre?
Wenn du den folgenden dummen Code nimmst:
%Vor%Kompilieren Sie es zum Objektformat und disassemblieren Sie es über objdump, dann machen Sie dasselbe, nachdem Sie "flüchtig" entfernt haben, gibt es keinen Unterschied (gemäß diff). Ist die volatile Deklaration zu nahe an der Stelle, an der sie überprüft oder modifiziert wurde, oder sollte ich immer nur einen atomaren Typ verwenden, wenn ich etwas volatiles deklariere? Beeinflussen einige Optimierungsflags das?
Beachten Sie, meine dumme Probe stimmt nicht vollständig mit meiner Frage überein, das ist mir klar. Ich versuche nur herauszufinden, ob GCC die Variable als volatil behandelt hat oder nicht, also studiere ich kleine Dumps, um den Unterschied zu finden.
Viele Compiler behandeln in manchen Situationen nicht so flüchtig, wie sie sollten. Wenn Sie viel mit flüchtigen Stoffen zu tun haben, um böse Überraschungen zu vermeiden, sehen Sie sich dieses Papier an: Volatiles werden falsch kompiliert, und was zu Mach etwas darüber . Es enthält auch die ziemlich gute Beschreibung der volatilen Rückendeckung mit den Zitaten aus dem Standard.
Um 100% sicher zu sein, und für solch ein einfaches Beispiel, überprüfen Sie die Baugruppenausgabe.
Versuchen Sie, die Variable außerhalb einer Schleife zu setzen und sie innerhalb der Schleife zu lesen. In einem nichtflüchtigen Fall könnte der Compiler ihn in ein Register schieben (oder vielleicht nicht) oder eine Kompilierungszeitkonstante oder etwas vor der Schleife machen, da er "weiß", dass er sich nicht ändert, wohingegen er, wenn er flüchtig ist, dies tut Lesen Sie es jedes Mal aus dem Variablenraum durch die Schleife.
Wenn Sie etwas als volatil deklarieren, sagen Sie dem Compiler grundsätzlich, bestimmte Optimierungen nicht vorzunehmen. Wenn Sie sich entschieden haben, diese Optimierungen nicht vorzunehmen, wissen Sie nicht, dass sie es nicht getan haben, weil es als flüchtig deklariert wurde, oder nur, dass es entschieden hat, dass diese Register für etwas anderes benötigt werden, oder es nicht tat Beachten Sie, dass es in eine Kompilierzeitkonstante umgewandelt werden könnte.
Soweit ich weiß, hilft volatile dem Optimierer. Zum Beispiel, wenn Ihr Code wie folgt aussieht:
%Vor%Die "while" -Schleife würde außerhalb der Binärdatei optimiert werden.
Aber wenn Sie 'x' als flüchtig definieren (dh volatile int x;
), dann wird der Compiler die Schleife in Ruhe lassen.
Ihre kleine Stichprobe reicht nicht aus, um etwas zu zeigen. Der Unterschied zwischen einer volatilen und einer nichtvariablen Variablen besteht darin, dass jede Ladung oder Speicherung im Code genau eine Ladung oder einen Speicher in der ausführbaren Datei für eine flüchtige Variable erzeugen muss, während der Compiler Lasten oder Speicher von nicht optimieren kann - flüchtige Variablen. Wenn Sie eine Ladung i in Ihrer Stichprobe erhalten, erwarte ich das für volatile und nicht volatile.
Um einen Unterschied zu zeigen, müssen Sie redundante Ladungen und / oder Speicher haben. Versuchen Sie etwas wie
%Vor%ich ändere zwischen nichtflüchtigen und volatilen. Möglicherweise müssen Sie eine gewisse Optimierungsebene aktivieren, um den Unterschied zu sehen.
Der Code dort hat drei Speicher und zwei Ladungen von i, die in einem Laden und wahrscheinlich in einem Laden optimiert werden können, wenn ich nicht flüchtig bin. Wenn i für flüchtig erklärt wird, sollten alle Speicher und Ladevorgänge in der Reihenfolge der Objekte angezeigt werden, unabhängig von der Optimierung. Wenn nicht, haben Sie einen Compilerfehler.
Es sollte immer es als flüchtig behandeln.
Der Grund dafür, dass der Code derselbe ist, besteht darin, dass volatile den Compiler nur anweist, die Variable bei jedem Zugriff auf den Speicher zu laden. Selbst wenn die Optimierung aktiviert ist, muss der Compiler immer noch einmal aus dem Speicher in den Code laden, den Sie geschrieben haben, da er den Wert von i zum Zeitpunkt der Kompilierung nicht ableiten kann. Wenn Sie wiederholt darauf zugreifen, sehen Sie einen Unterschied.
Jeder moderne Compiler hat mehrere Stufen. Eine der relativ einfachen aber interessanten Fragen ist, ob die Deklaration der Variablen selbst richtig geparst wurde. Dies ist einfach, da die C ++ - Namensänderung abhängig von der Flüchtigkeit variieren sollte. Wenn Sie also zweimal kompilieren und einmal flüchtig definiert sind, sollten sich die Symboltabellen etwas unterscheiden.
Lesen Sie den Standard, bevor Sie ihn falsch schreiben oder ablehnen. Hier ist ein Zitat aus n2798:
7.1.6.1 Die cv-Qualifier
7 Hinweis: volatile ist ein Hinweis auf die Implementierung, um eine aggressive Optimierung des Objekts zu vermeiden, da der Wert des Objekts möglicherweise durch eine Implementierung nicht erfassbar geändert wird. Eine detaillierte Semantik finden Sie in 1.9. Im Allgemeinen soll die Semantik von volatile in C ++ die gleiche sein wie in C.
Das Schlüsselwort volatile
dient als Hinweis. Ähnlich wie das register
-Schlüsselwort. % Co_de% fordert den Compiler jedoch auf, alle Optimierungen in Schach zu halten. Auf diese Weise wird keine Kopie der Variablen in einem Register oder Cache gespeichert (um die Zugriffsgeschwindigkeit zu optimieren), sondern sie wird immer dann aus dem Speicher abgerufen, wenn Sie danach gefragt werden.
Da gibt es so viel Verwirrung: einige mehr. Der C99-Standard besagt tatsächlich, dass ein flüchtiges qualifiziertes Objekt jedes Mal nachgeschlagen werden muss, wenn es gelesen wird und so weiter, wie andere es bemerkt haben. Aber es gibt auch einen anderen Abschnitt, der besagt, dass die Definition eines flüchtigen Zugriffs die Implementierung definiert. Ein Compiler, der die Hardware in- und auswendig kennt, weiß zum Beispiel, wenn Sie eine automatische volatile qualifizierte Variable haben und deren Adresse niemals vergeben wird, dass sie nicht in eine sensible Speicherregion gestellt wird und mit ziemlicher Sicherheit ignoriert wird der Hinweis und optimiere es weg.
Dieses Schlüsselwort findet Verwendung in volatile
und setjmp
Art der Fehlerbehandlung. Das einzige, was Sie beachten müssen, ist Folgendes: Sie geben das flüchtige Schlüsselwort an, wenn Sie denken, dass sich die Variable ändern kann. Das heißt, Sie könnten ein gewöhnliches Objekt nehmen und mit ein paar Würfen fertig werden.
Eine andere Sache, die man im Auge behalten sollte, ist die Definition dessen, was einen flüchtigen Zugriff ausmacht, der von der Norm der Implementierung überlassen wird.
Wenn Sie wirklich eine andere Assembly mit Optimierung kompilieren wollten