Warum ist ein Point-to-Volatile-Zeiger wie „volatile int * p“ nützlich?


77

volatilesoll den Compiler anweisen, die Referenz nicht zu optimieren, damit bei jedem Lesen / Schreiben nicht der im Register gespeicherte Wert verwendet wird, sondern ein echter Speicherzugriff erfolgt. Ich kann verstehen, dass es für eine gewöhnliche Variable nützlich ist, verstehe aber nicht, wie volatilesich ein Zeiger auswirkt.

volatile int *p = some_addr;
int a = *p; // CPU always has to load the address, then does a memory access anyway, right?

Was ist der Unterschied, wenn es als deklariert wurde int *p = some_addr?

Antworten:


140

Ein Zeiger des Formulars

volatile int* p;

ist ein Zeiger auf einen int, den der Compiler als behandelt volatile. Dies bedeutet, dass der Compiler davon ausgeht, dass sich die Variable, auf pdie zeigt, möglicherweise geändert hat, auch wenn der Quellcode nichts enthält, was darauf hindeutet, dass dies auftreten könnte. Wenn ich beispielsweise pauf eine reguläre Ganzzahl verweise, ist *pdem Compiler bei jedem Lesen oder Schreiben bewusst, dass sich der Wert möglicherweise unerwartet geändert hat.

Es gibt noch einen Anwendungsfall für a volatile int*: Wenn Sie ein intas deklarieren volatile, sollten Sie nicht mit einem regulären darauf zeigen int*. Zum Beispiel ist dies eine schlechte Idee:

volatile int myVolatileInt;
int* ptr = &myVolatileInt; // Bad idea!

Der Grund dafür ist, dass sich der C-Compiler nicht mehr daran erinnert, dass die Variable, auf die gezeigt wird, ptris ist volatile, sodass der Wert von *pin einem Register möglicherweise falsch zwischengespeichert wird. In C ++ ist der obige Code ein Fehler. Stattdessen solltest du schreiben

volatile int myVolatileInt;
volatile int* ptr = &myVolatileInt; // Much better!

Jetzt merkt sich der Compiler, dass ptrer auf a zeigt, und volatile intversucht daher nicht (oder sollte nicht!), Die Zugriffe durch zu optimieren *ptr.

Ein letztes Detail - der Zeiger, den Sie besprochen haben, ist ein Zeiger auf a volatile int. Sie können dies auch tun:

int* volatile ptr;

Dies besagt, dass der Zeiger selbst ist volatile, was bedeutet, dass der Compiler nicht versuchen sollte, den Zeiger im Speicher zwischenzuspeichern oder den Zeigerwert zu optimieren, da der Zeiger selbst möglicherweise durch etwas anderes (Hardware usw.) neu zugewiesen wird. Sie können diese kombinieren zusammen, wenn Sie dieses Biest bekommen möchten:

volatile int* volatile ptr;

Dies besagt, dass sowohl der Zeiger als auch der Zeiger unerwartet geändert werden könnten. Der Compiler kann den Zeiger selbst nicht optimieren und er kann nicht optimieren, auf was gezeigt wird.

Hoffe das hilft!


Ich denke du meinst "du solltest NICHT mit einem regulären int * darauf zeigen"
markgz

1
Ich denke, es ist auch ein Fehler in C, aber C-Compiler neigen weniger dazu, sich über Typinkongruenzen zu beschweren.
Chris Lutz

Vielen Dank. Es ist also kein Unterschied, ob es für mein Beispiel "flüchtig" gibt, oder? Aber wenn ein anderes Statemenet "int b = * p" folgt, macht es einen Unterschied, oder? Insbesondere kann "b" unter Verwendung eines Registers initialisiert werden, das "* p" speichert, anstatt eine echte Speicherreferenz durchzuführen.
Unendlich

1
@ SetTimer- Das hängt wirklich davon ab, was do_something_elseist. Wenn der Compiler vollständig davon überzeugt sein könnte, dass er do_something_elseden Wert von nie geändert hat x, könnte er den Wert von definitiv *paus einem Register lesen, wenn er dies wünscht. Ich bezweifle, dass dies für jeden vernünftigen Code und die meisten Compiler tatsächlich passieren würde, aber theoretisch wäre es möglich. Ist das sinnvoll?
Templatetypedef

1
@olaf Fehlerbericht Zusammenfassung für C11 Version 1.10 Datum: April 2016 DR 476 flüchtige Semantik für Werte 04/2016 Open
philipxy

9

Dieser Code volatile int *p = some_addrdeklariert einen Zeiger auf a volatile int. Der Zeiger selbst ist nicht volatile.

In dem unwahrscheinlichen Fall, dass der Zeiger sowohl flüchtig als auch int sein muss, müssen Sie Folgendes verwenden:

volatile int * volatile p;

Ich kann mir keine Situation vorstellen, in der Sie das brauchen würden.


4
Beispiel: Ich verwende 'volatile uint8_t * volatile pData' im ISR-Code, der den Zeiger und die Daten, auf die er zeigt, ändert. Der Zeiger wird durch den Hauptcode gesetzt, und sowohl der Zeiger als auch die Daten werden später gelesen.
Christoph

2

Zur Nützlichkeit von flüchtigen Stoffen: Dies ist erforderlich, wenn Sie den Speicher überprüfen müssen, der von der Hardware wie einem seriellen Schnittstellencontroller geändert wird. Es hat seine Anwendung in der Welt der eingebetteten Systeme, in denen Sie sehr nah an der Hardware arbeiten, ohne dass ein Betriebssystem dazwischen liegt.


1
Oder wenn Sie das Betriebssystem entwickeln.
Atilla Filiz
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.