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

Lesezeit: 4 Minuten

Benutzeravatar von Infinite
Unendlich

volatile soll dem Compiler mitteilen, die Referenz nicht zu optimieren, so dass jeder Lese-/Schreibvorgang nicht den im Register gespeicherten Wert verwendet, sondern einen echten Speicherzugriff durchführt. Ich kann verstehen, dass es für eine gewöhnliche Variable nützlich ist, verstehe aber nicht, wie volatile beeinflusst einen Zeiger.

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?

Benutzeravatar von templatetypedef
Vorlagentypdef

Ein Zeiger des Formulars

volatile int* p;

ist ein Zeiger auf ein int die der Compiler behandeln wird volatile. Das bedeutet, dass der Compiler davon ausgeht, dass es für die Variable möglich ist, dass p darauf hindeutet, sich geändert zu haben, auch wenn nichts im Quellcode darauf hindeutet, dass dies geschehen könnte. Zum Beispiel, wenn ich setze p auf eine reguläre Ganzzahl zeigen, dann jedes Mal, wenn ich lese oder schreibe *p ist sich der Compiler bewusst, dass sich der Wert möglicherweise unerwartet geändert hat.

Es gibt noch einen weiteren Anwendungsfall für a volatile int*: Wenn Sie eine erklären int wie volatiledann sollten Sie nicht mit einem regulären darauf zeigen int*. Das ist zum Beispiel 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 by zeigt ptr ist volatilesodass der Wert von möglicherweise zwischengespeichert wird *ptr in einem Register falsch. Tatsächlich ist der obige Code in C++ ein Fehler. Stattdessen sollten Sie schreiben:

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

Nun, der Compiler merkt sich das ptr zeigt auf a volatile intalso wird (oder sollte nicht!) versucht werden, Zugriffe durch zu optimieren *ptr.

Ein letztes Detail – der von Ihnen besprochene Zeiger ist ein Zeiger auf a volatile int. Sie können dies auch tun:

int* volatile ptr;

Dies sagt, dass der Zeiger selbst ist volatilewas bedeutet, dass der Compiler nicht versuchen sollte, den Zeiger im Speicher zwischenzuspeichern oder den Zeigerwert zu optimieren, da der Zeiger selbst möglicherweise von etwas anderem (Hardware usw.) neu zugewiesen wird. Sie können diese kombinieren, wenn Sie möchten Hol dir dieses Biest:

volatile int* volatile ptr;

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

Hoffe das hilft!

  • Ich denke, es ist auch ein Fehler in C, aber C-Compiler neigen weniger dazu, sich über Typenkonflikte zu beschweren.

    – Chris Lutz

    29. März 2012 um 23:53 Uhr

  • Vielen Dank. Es ist also egal, ob es für mein Beispiel “volatile” gibt, oder? Aber wenn eine weitere Anweisung “int b = *p” folgt, macht das einen Unterschied, oder? Insbesondere kann “b” unter Verwendung eines Registers initialisiert werden, das “*p” speichert, anstatt eine echte Speicherreferenz durchzuführen.

    – Unendlich

    29. März 2012 um 23:55 Uhr

  • @SetTimer- Die C-Spezifikation ist so allgemein, dass Ideen wie “Caches”, “Register” und “Speicherreferenzen” nicht existieren. Der Compiler wird wahrscheinlich die Variable nicht in einem Register halten, aber es könnte theoretisch schlau genug sein, um zu bemerken, dass die int worauf gezeigt wird, ist nicht gekennzeichnet volatile und würde somit den Code identisch mit und ohne kompilieren volatile.

    – Vorlagentypdef

    29. März 2012 um 23:57 Uhr

  • @SetTimer- Das hängt wirklich davon ab, was do_something_else ist. Wenn der Compiler davon vollkommen überzeugt werden könnte do_something_else nie den Wert von geändert xdann könnte es definitiv den Wert von lesen *p aus einem Register, wenn es wollte. 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?

    – Vorlagentypdef

    30. März 2012 um 0:16 Uhr

  • @olaf Defect Report Summary für C11 Version 1.10 Datum: April 2016 DR 476 flüchtige Semantik für lvalues 04/2016 geöffnet

    – Philippie

    19. Februar 2017 um 2:07 Uhr

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

In dem unwahrscheinlichen Fall, dass Sie sowohl den Zeiger als auch den int flüchtig benötigen, müssen Sie Folgendes verwenden:

volatile int * volatile p;

Ich kann mir keine Situation vorstellen, in der Sie das verwenden müssten.

  • Beispiel: Ich verwende ‘volatile uint8_t* volatile pData’ in ISR-Code, der den Zeiger und die Daten, auf die er zeigt, modifiziert. Der Zeiger wird durch den Hauptcode gesetzt, und sowohl der Zeiger als auch die Daten werden später gelesen.

    – Christoph

    24. Februar 2013 um 0:24 Uhr

Zur Nützlichkeit von volatile: Dies wird benötigt, wenn Sie Speicher überprüfen müssen, der durch Hardware wie einen seriellen Schnittstellencontroller modifiziert wird. Es hat seine Anwendung in der Welt der eingebetteten Systeme, wo Sie sehr nah an der Hardware arbeiten, ohne ein Betriebssystem dazwischen.

  • Oder wenn Sie das Betriebssystem entwickeln.

    – Atilla Filiz

    21. Juni 2019 um 8:24 Uhr

1419310cookie-checkWarum ist ein Point-to-Volatile-Zeiger wie “volatile int * p” nützlich?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy