web-dev-qa-db-de.com

Unterschied zwischen const und const volatile

Wenn wir eine Variable jedes Mal als volatile deklarieren, wenn der neue Wert aktualisiert wird
Wenn wir eine Variable als const deklarieren, wird der Wert dieser Variablen nicht geändert

Dann const volatile int temp;
Was nützt es, die Variable temp wie oben zu deklarieren?
Was passiert, wenn wir als const int temp Deklarieren?

79
user559208

Ein Objekt, das mit const volatile Markiert ist, darf durch den Code nicht geändert werden (ein Fehler wird aufgrund des Qualifizierers const ausgelöst) - zumindest nicht durch diesen bestimmten Namen/Zeiger.

Der Teil volatile des Qualifiers 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, in die jedoch nicht geschrieben werden kann (oder in die möglicherweise ein Fehler vorliegt).

Ein Beispiel könnte das Statusregister für eine serielle Schnittstelle sein. Verschiedene Bits zeigen an, ob ein Zeichen auf das Lesen wartet oder ob das Senderegister bereit ist, ein neues Zeichen zu akzeptieren (dh - es ist leer). Jeder Lesevorgang in diesem Statusregister kann zu einem anderen Wert führen, je nachdem, was an der Hardware des seriellen Anschlusses noch 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 vorherigen Lesevorgang. ' t Sie über Änderungen im Hardware-Status informieren.

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 volatile markiert wurden, können einige Probleme auftreten:

  • der while-Schleifentest liest das Statusregister möglicherweise nur einmal, da der Compiler davon ausgehen kann, dass sich nichts ändern wird, worauf er hinweist. Wenn Sie die Funktion aufgerufen haben, während auf der UART -Hardware kein Zeichen gewartet hat, könnte dies zu einer Endlosschleife führen, die auch beim Empfang eines Zeichens nicht gestoppt wurde.
  • das Lesen des Empfangsregisters kann vom Compiler vor die while-Schleife verschoben werden. Auch hier gibt es keinen Grund dafür, dass *recv_reg von der Schleife geändert wird die Schleife betreten.

Das Qualifikationsmerkmal volatile stellt sicher, dass diese Optimierungen nicht vom Compiler ausgeführt werden.

123
Michael Burr
  • volatile weist den Compiler an, den Code für die Variable nicht zu optimieren, normalerweise, wenn wir wissen, dass er von "außen" geändert werden kann, z. von einem anderen Thread.
  • const teilt dem Compiler mit, dass es dem Programm untersagt ist, den Wert der Variablen zu ändern.
  • const volatile ist eine ganz besondere Sache, die Sie wahrscheinlich genau 0-mal in Ihrem Leben sehen werden (tm). Es ist zu erwarten, dass das Programm den Wert der Variablen nicht ändern kann, der Wert jedoch von außen geändert werden kann, sodass für die Variable keine Optimierungen durchgeführt werden.
34
mingos

Nicht weil die Variable const ist, darf sie sich zwischen zwei Sequenzpunkten nicht geändert haben.

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

24
Alexandre C.

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;

... indem Sie den Konstantenwert vorberechnen und eine sofortige Montageanweisung verwenden oder die Konstante von einem nahe gelegenen Ort laden, sodass alle Aktualisierungen des ursprünglichen CANID-Werts im Konfigurations-Flash-Bereich ignoriert werden. CANID muss konstant flüchtig sein.

7
push2eject

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

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

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

Tatsächlich nennt der C-Standard ein Beispiel für eine gültige Deklaration, die sowohl const als auch volatile ist. Das Beispiel ist

"Extern const volatile int real_time_clock;"

dabei kann real_time_clock von der Hardware geändert, aber nicht zugewiesen, inkrementiert 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.

5
user2903536

Dieser Artikel beschreibt die Szenarien, in denen Sie const- und volatile-Qualifizierer kombinieren möchten.

http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/

3
balajimc55

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

volatile bedeutet, dass sich die Variable jederzeit ändern kann und daher möglicherweise keine zwischengespeicherten Werte verwendet werden. Jeder Zugriff auf die Variable muss auf ihre Speicheradresse erfolgen.

Da die Frage als "eingebettet" markiert ist und angenommen wird, dass temp eine vom Benutzer deklarierte Variable ist, kein 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-Schreib-Datenspeicher (RAM) als auch einen nichtflüchtigen Nur-Lese-Datenspeicher aufweist, beispielsweise einen FLASH-Speicher in einer von-Neumann-Architektur, bei dem sich Daten- und Programmraum einen gemeinsamen Daten- und Adressbus teilen.

Wenn Sie deklarieren, dass const temp Einen Wert hat (zumindest wenn dieser von 0 abweicht), weist der Compiler die Variable einer Adresse im FLASH-Bereich zu, auch wenn sie einem RAM zugewiesen wurde. adresse benötigt es weiterhin FLASH-Speicher, um den Anfangswert der Variablen zu speichern, wodurch die Adresse RAM eine Verschwendung von Speicherplatz darstellt, 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 Variable, die in (read-ony) FLASH gespeichert ist. Sie wird zur Compiler-Zeit auf 0 initialisiert. Zwischengespeicherte Werte können 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 Variable, die in (read-ony) FLASH gespeichert und zur Compiler-Zeit auf 0 initialisiert wird. Zwischengespeicherte Werte werden NICHT verwendet

Hier kommt der nützliche Teil:

Heutzutage haben die meisten Embedded-Prozessoren die Möglichkeit, über einen speziellen Funktionsbaustein Änderungen an ihrem nichtflüchtigen Nur-Lese-Speicher vorzunehmen. In diesem Fall kann const int temp Zur Laufzeit geändert werden, nicht jedoch direkt. Auf andere Weise kann eine Funktion den Wert an der Adresse ändern, an der temp gespeichert ist.

Ein praktisches Beispiel wäre die Verwendung von temp für die Seriennummer des Geräts. Wenn der eingebettete Prozessor zum ersten Mal ausgeführt wird, ist temp gleich 0 (oder dem deklarierten Wert), und eine Funktion kann anhand dieser Tatsache einen Test während der Produktion ausführen und bei Erfolg die Zuweisung einer Seriennummer und anfordern Ändern Sie den Wert von temp mit einer speziellen Funktion. Einige Prozessoren haben einen speziellen Adressbereich mit OTP-Speicher (einmalig programmierbar).

Aber hier kommt der Unterschied:

Wenn const int temp Eine veränderbare ID anstelle einer einmalig programmierbaren Seriennummer ist und NICHT als volatile deklariert ist, wird möglicherweise ein zwischengespeicherter Wert bis zum nächsten Start verwendet, was bedeutet, dass die neue ID möglicherweise nicht vorhanden ist gültig bis zum nächsten Neustart, oder noch schlimmer, einige Funktionen verwenden möglicherweise den neuen Wert, während andere einen älteren zwischengespeicherten Wert verwenden, bis ein Neustart durchgeführt wird. Wenn const int temp IS als voltaile deklariert wurde, wird die ID-Änderung sofort wirksam.

3
Michael Kusch

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

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

Wir verwenden das Schlüsselwort 'const' für eine Variable, wenn das Programm diese nicht ändern soll. Während wir eine Variable als "const volatile" deklarieren, weisen wir das Programm an, sie nicht zu ändern, und den Compiler, dass diese Variable unerwartet durch Eingaben von außen geändert werden kann.

1
Ali

Einfach ausgedrückt kann der Wert in der 'const volatile'-Variablen nicht programmgesteuert geändert werden, sondern kann durch Hardware geändert werden. Flüchtig ist hier jede Compileroptimierung zu verhindern.

1
rajeshsam