2012-03-29 6 views
57

volatile ist der Compiler angewiesen, die Referenz nicht zu optimieren, so dass jeder Lese-/Schreibvorgang nicht den im Register gespeicherten Wert verwendet, sondern einen echten Speicherzugriff. Ich kann verstehen, dass es für einige gewöhnliche Variable nützlich ist, aber nicht verstehe, wie volatile einen Zeiger betrifft.Warum ist ein Point-to-Volatile-Zeiger wie "volatile int * p" nützlich?

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 sie als int *p = some_addr erklärt wurde?

Antwort

101

Ein Zeiger von der Form

volatile int* p; 

ein Zeiger auf ein int, dass der Compiler als volatile behandeln. Das bedeutet, dass der Compiler davon ausgehen wird, dass die Variable, die auf zeigt, geändert werden kann, auch wenn nichts im Quellcode darauf hindeutet, dass dies der Fall sein könnte. Wenn ich z. B. so einstellen, dass er auf eine reguläre Ganzzahl zeigt, merkt der Compiler bei jedem Lesen oder Schreiben von *p, dass sich der Wert möglicherweise unerwartet geändert hat.

Es gibt einen weiteren Anwendungsfall für eine volatile int*: Wenn Sie ein int als volatile erklären, dann sollten Sie nicht mit einem regelmäßigen int* darauf verweisen. Zum Beispiel ist dies eine schlechte Idee:

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

Der Grund dafür ist, dass die C-Compiler nicht mehr erinnern, dass der Variable auf deutete durch ptr ist volatile, so könnte es den Wert von *p in einem Register-Cache falsch . Tatsächlich ist der obige Code in C++ ein Fehler. Stattdessen sollten Sie

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

Jetzt schreiben, erinnert sich der Compiler, dass ptr Punkte bei einer volatile int, so wird es nicht (oder nicht!) Versuchen Zugriffe durch *ptr zu optimieren.

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

int* volatile ptr; 

Diese besagt, dass der Zeiger selbstvolatile ist, was bedeutet, dass der Compiler nicht versuchen sollte, den Zeiger im Speicher zwischengespeichert werden oder versuchen, den Zeigerwert zu optimieren, da der Zeiger selbst bekommen könnte durch etwas anderes (Hardware, ein anderer Thread, etc.) zugewiesen Sie diese zusammen kombinieren können, wenn Sie dieses Tier bekommen möchten:

volatile int* volatile ptr; 

Dies sagt, dass sowohl die Zeiger und die pointee könnte unerwartet umziehen . Der Compiler kann den Zeiger selbst nicht optimieren, und er kann nicht optimieren, worauf er hinweist.

Hoffe, das hilft!

+0

Ich denke, du meinst "du solltest es NICHT mit einem normalen int * zeigen" – markgz

+0

@ markgz- Whoops! Ja das ist richtig. Fest. – templatetypedef

+0

Ich denke, es ist auch ein Fehler in C, aber C-Compiler neigen weniger dazu, sich über Typkonflikte zu beklagen. –

6

Dieser Code volatile int *p = some_addr deklariert einen Zeiger auf eine volatile int. Der Zeiger selbst ist nicht volatile.

Im unwahrscheinlichen Fall, dass Sie den Zeiger benötigt sowie der int volatil zu sein, würden Sie verwenden müssen:

volatile int * volatile p; 

ich nicht von einer Situation denken kann, wo Sie verwenden müssen, würde das .

+2

Beispiel: I 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 Zeiger und Daten werden später gelesen. – Christoph