Unterschied zwischen const & const flüchtig

86

Wenn wir eine Variable wie volatilejedes Mal deklarieren, wenn der neue Wert aktualisiert wird.
Wenn wir eine Variable als deklarieren, constwird der Wert dieser Variablen nicht geändert

Dann const volatile int temp;
Was ist die Verwendung von Deklarieren der Variablen tempwie oben?
Was passiert, wenn wir als deklarieren const int temp?

user559208
quelle
Sie würden nicht const volatile int temp;im Blockbereich (dh im Inneren { }) verwenden, es hat dort keine Verwendung.
MM

Antworten:

141

Ein als markiert gekennzeichnetes Objekt const volatiledarf vom Code nicht geändert werden (ein Fehler wird aufgrund des constQualifizierers ausgelöst) - zumindest durch diesen bestimmten Namen / Zeiger.

Der volatileTeil des Qualifizierers bedeutet, dass der Compiler den Zugriff auf das Objekt nicht optimieren oder neu anordnen kann.

In einem eingebetteten System wird dies normalerweise verwendet, um auf Hardwareregister zuzugreifen, die von der Hardware gelesen und aktualisiert werden können, aber keinen Sinn zum Schreiben haben (oder möglicherweise ein Fehler zum Schreiben sind).

Ein Beispiel könnte das Statusregister für eine serielle Schnittstelle sein. Verschiedene Bits zeigen an, ob ein Zeichen darauf wartet, gelesen zu werden, oder ob das Übertragungsregister bereit ist, ein neues Zeichen aufzunehmen (dh - es ist leer). Jeder Lesevorgang dieses Statusregisters kann zu einem anderen Wert führen, je nachdem, was sonst noch in der Hardware der seriellen Schnittstelle aufgetreten ist.

Es macht keinen Sinn, in das Statusregister zu schreiben (abhängig von der jeweiligen Hardwarespezifikation), aber Sie müssen sicherstellen, dass jeder Lesevorgang des Registers zu einem tatsächlichen Lesevorgang der Hardware führt - unter Verwendung eines zwischengespeicherten Werts aus einem zuvor gewonnenen Lesevorgang. ' Sie informieren Sie nicht über Änderungen im Hardwarestatus.

Ein kurzes Beispiel:

unsigned int const volatile *status_reg; // assume these are assigned to point to the 
unsigned char const volatile *recv_reg;  //   correct hardware addresses


#define UART_CHAR_READY 0x00000001

int get_next_char()
{
    while ((*status_reg & UART_CHAR_READY) == 0) {
        // do nothing but spin
    }

    return *recv_reg;
}

Wenn diese Zeiger nicht als solche markiert volatilewären, könnten einige Probleme auftreten:

  • Der while-Schleifentest liest das Statusregister möglicherweise nur einmal, da der Compiler davon ausgehen kann, dass sich alles, worauf er zeigt, niemals ändern wird (der while-Schleifentest oder die Schleife selbst können nichts daran ändern). Wenn Sie die Funktion eingegeben haben, während in der UART-Hardware kein Zeichen auf Sie gewartet hat, könnten Sie in eine Endlosschleife geraten, die selbst beim Empfang eines Zeichens nie gestoppt wurde.
  • Das Lesen des Empfangsregisters könnte vom Compiler vor die while-Schleife verschoben werden. Da die Funktion nichts enthält, was darauf hinweist, dass sie *recv_regvon der Schleife geändert wurde, gibt es keinen Grund, warum sie vor dem Eintritt in die Schleife nicht gelesen werden kann.

Die volatileQualifizierer stellen sicher, dass diese Optimierungen nicht vom Compiler durchgeführt werden.

Michael Burr
quelle
4
+1 zur Erklärung. Und ich habe eine Frage: Was ist mit const volatile Methoden? Wenn ich eine Klasse habe, auf die viele Threads zugreifen (obwohl der Zugriff mit Mutex synchronisiert ist), müssen meine const-Methoden auch flüchtig sein (da einige Variablen von anderen Threads geändert werden könnten)
Sasa
37
  • volatile wird den Compiler anweisen, den Code für die Variable nicht zu optimieren, normalerweise wenn wir wissen, dass sie von "außen" geändert werden kann, z. B. durch einen anderen Thread.
  • const teilt dem Compiler mit, dass es dem Programm verboten ist, den Wert der Variablen zu ändern.
  • const volatileist eine ganz besondere Sache, die Sie wahrscheinlich genau 0 Mal in Ihrem Leben sehen werden (tm). Wie zu erwarten ist, bedeutet dies, dass das Programm den Wert der Variablen nicht ändern kann, der Wert jedoch von außen geändert werden kann, sodass keine Optimierungen an der Variablen durchgeführt werden.
Mingos
quelle
11
Ich hätte gedacht, dass volatileVariablen normalerweise das sind, was passiert, wenn Sie anfangen, mit Hardware zu spielen, nicht mit anderen Threads. Wo ich gesehen habe const volatile, ist in Dingen wie speicherabgebildeten Statusregistern oder dergleichen verwendet.
NUR MEINE RICHTIGE MEINUNG
2
Natürlich hast du absolut Recht, Multithreading ist nur ein Beispiel, aber nicht das einzige :).
Mingos
24
Wenn Sie mit eingebetteten Systemen arbeiten, werden Sie dies sehr oft sehen.
Daniel Grillo
25

Nicht weil die Variable const ist, hat sie sich möglicherweise nicht zwischen zwei Sequenzpunkten geändert.

Konstanz ist ein Versprechen, dass Sie den Wert nicht ändern, nicht, dass der Wert nicht geändert wird.

Alexandre C.
quelle
8
Plus eins für den Hinweis, dass constDaten nicht "konstant" sind.
Bogdan Alexandru
7

Ich musste dies in einer eingebetteten Anwendung verwenden, in der sich einige Konfigurationsvariablen in einem Bereich des Flash-Speichers befinden, der von einem Bootloader aktualisiert werden kann. Diese Konfigurationsvariablen sind zur Laufzeit 'konstant', aber ohne das flüchtige Qualifikationsmerkmal würde der Compiler so etwas optimieren ...

cantx.id = 0x10<<24 | CANID<<12 | 0;

... durch Vorberechnung des Konstantenwerts und Verwendung einer sofortigen Montageanweisung oder Laden der Konstante von einem nahe gelegenen Ort, sodass Aktualisierungen des ursprünglichen CANID-Werts im Konfigurations-Flash-Bereich ignoriert werden. CANID muss konstant flüchtig sein.

push2eject
quelle
7

In C sind const und volatile Typqualifizierer und diese beiden sind unabhängig.

Grundsätzlich bedeutet const, dass der Wert vom Programm nicht geändert werden kann.

Und volatil bedeutet, dass sich der Wert plötzlich ändert (möglicherweise von außerhalb des Programms).

Tatsächlich erwähnt der C-Standard ein Beispiel für eine gültige Deklaration, die sowohl konstant als auch flüchtig ist. Das Beispiel ist

"Externe const volatile int real_time_clock;"

Dabei kann real_time_clock von der Hardware geändert werden, jedoch nicht zugewiesen, erhöht oder dekrementiert werden.

Wir sollten also const und volatile bereits getrennt behandeln. Außerdem gilt dieses Typqualifikationsmerkmal auch für struct, union, enum und typedef.

user2903536
quelle
5

Sie können const und volatile zusammen verwenden. Wenn beispielsweise angenommen wird, dass 0x30 der Wert eines Ports ist, der nur durch externe Bedingungen geändert wird, würde die folgende Deklaration die Möglichkeit versehentlicher Nebenwirkungen verhindern:

const volatile char *port = (const volatile char *)0x30;
Schritt
quelle
3

constbedeutet, dass die Variable nicht durch den c-Code geändert werden kann, nicht, dass sie nicht geändert werden kann. Dies bedeutet, dass keine Anweisung in die Variable schreiben kann, ihr Wert sich jedoch möglicherweise noch ändert.

volatilebedeutet, dass sich die Variable jederzeit ändern kann und daher keine zwischengespeicherten Werte verwendet werden können; Jeder Zugriff auf die Variable muss an ihrer Speicheradresse ausgeführt werden.

Da die Frage mit "eingebettet" gekennzeichnet ist und angenommen wird, dass tempes sich um eine vom Benutzer deklarierte Variable handelt, nicht um ein hardwarebezogenes Register (da diese normalerweise in einer separaten .h-Datei behandelt werden), sollten Sie Folgendes berücksichtigen:

Ein eingebetteter Prozessor, der sowohl einen flüchtigen Lese- / Schreibdatenspeicher (RAM) als auch einen nichtflüchtigen Nur-Lese-Datenspeicher aufweist, beispielsweise einen FLASH-Speicher in einer von-Neumann-Architektur, in dem Daten- und Programmraum einen gemeinsamen Daten- und Adressbus gemeinsam nutzen.

Wenn Sie const tempeinen Wert deklarieren (zumindest wenn dieser von 0 abweicht), weist der Compiler die Variable einer Adresse im FLASH-Bereich zu, da er selbst dann, wenn er einer RAM-Adresse zugewiesen wurde, noch FLASH-Speicher benötigt, um den Anfangswert zu speichern Dies macht die RAM-Adresse zu einer Platzverschwendung, da alle Operationen schreibgeschützt sind.

Als Folge:

int temp;ist eine im RAM gespeicherte Variable, die beim Start (cstart) auf 0 initialisiert wird. Es können zwischengespeicherte Werte verwendet werden.

const int temp;ist eine in (schreibgeschützt) FLASH gespeicherte Variable, die zur Compilerzeit auf 0 initialisiert wird. Es können zwischengespeicherte Werte verwendet werden.

volatile int temp; ist eine im RAM gespeicherte Variable, die beim Start (cstart) auf 0 initialisiert wird. Zwischengespeicherte Werte werden NICHT verwendet.

const volatile int temp; ist eine in (schreibgeschützt) FLASH gespeicherte Variable, die zur Compilerzeit auf 0 initialisiert wird. Zwischengespeicherte Werte werden NICHT verwendet

Hier kommt der nützliche Teil:

Heutzutage haben die meisten Embedded-Prozessoren die Möglichkeit, Änderungen an ihrem schreibgeschützten nichtflüchtigen Speicher mithilfe eines speziellen Funktionsbausteins const int tempvorzunehmen. In diesem Fall können Änderungen zur Laufzeit vorgenommen werden, obwohl dies nicht direkt möglich ist. Auf andere Weise kann eine Funktion den Wert an der Adresse ändern, an der sie tempgespeichert ist.

Ein praktisches Beispiel wäre die Verwendung tempder Seriennummer des Geräts. tempWenn der eingebettete Prozessor zum ersten Mal ausgeführt wird, ist er gleich 0 (oder dem deklarierten Wert), und eine Funktion kann diese Tatsache verwenden, um einen Test während der Produktion auszuführen. Wenn dies erfolgreich ist, können Sie eine Seriennummer zuweisen und den Wert tempvon mittels ändern einer besonderen Funktion. Einige Prozessoren haben dafür einen speziellen Adressbereich mit OTP-Speicher (einmalig programmierbar).

Aber hier kommt der Unterschied:

Wenn const int tempes sich um eine modifizierbare ID anstelle einer einmalig programmierbaren Seriennummer handelt und NICHT deklariert ist volatile, wird möglicherweise ein zwischengespeicherter Wert bis zum nächsten Start verwendet, was bedeutet, dass die neue ID möglicherweise bis zum nächsten Neustart oder, noch schlimmer, einigen Funktionen nicht gültig ist verwendet möglicherweise den neuen Wert, während andere möglicherweise einen älteren zwischengespeicherten Wert bis zum Neustart verwenden. Wenn const int tempIS deklariert ist voltaile, wird die ID-Änderung sofort wirksam.

Michael Kusch
quelle
Wow, diese Antwort ist lang
2

In einfachen Worten, der Wert in der Variablen 'const volatile' kann nicht programmgesteuert geändert werden, sondern kann durch Hardware geändert werden. Flüchtig ist hier, um eine Compileroptimierung zu verhindern.

Rajeshsam
quelle
1

Wir verwenden das Schlüsselwort 'const' für eine Variable, wenn das Programm sie nicht ändern soll. Wenn wir eine Variable als 'const volatile' deklarieren, weisen wir das Programm an, sie nicht zu ändern, und den Compiler, dass diese Variable aufgrund von Eingaben aus der Außenwelt unerwartet geändert werden kann.

Ali
quelle