Différence entre const et const volatile

89

Si nous déclarons une variable comme à volatilechaque fois que la nouvelle valeur est mise à jour
Si nous déclarons une variable comme, constla valeur de cette variable ne sera pas modifiée

Alors, const volatile int temp;
quelle est l'utilité de déclarer la variable tempcomme ci-dessus?
Que se passe-t-il si nous déclarons comme const int temp?

user559208
la source
Vous n'utiliseriez pas const volatile int temp;à la portée du bloc (c'est-à-dire à l'intérieur { }), cela n'a aucune utilité là-bas.
MM

Réponses:

145

Un objet marqué comme const volatilene pourra pas être modifié par le code (une erreur sera générée en raison du constqualificatif) - au moins via ce nom / pointeur particulier.

La volatilepartie du qualificatif signifie que le compilateur ne peut pas optimiser ou réorganiser l'accès à l'objet.

Dans un système embarqué, cela est généralement utilisé pour accéder aux registres matériels qui peuvent être lus et mis à jour par le matériel, mais qui n'ont aucun sens pour écrire (ou peuvent être une erreur d'écriture).

Un exemple pourrait être le registre d'état pour un port série. Divers bits indiqueront si un caractère attend d'être lu ou si le registre de transmission est prêt à accepter un nouveau caractère (c'est-à-dire - il est vide). Chaque lecture de ce registre d'état peut entraîner une valeur différente en fonction de ce qui s'est produit d'autre dans le matériel du port série.

Cela n'a aucun sens d'écrire dans le registre d'état (en fonction de la spécification matérielle particulière), mais vous devez vous assurer que chaque lecture du registre entraîne une lecture réelle du matériel - en utilisant une valeur mise en cache d'une lecture précédente gagnée ' t vous informer des changements dans l'état du matériel.

Un exemple rapide:

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;
}

Si ces pointeurs n'étaient pas marqués comme étant volatile, quelques problèmes peuvent survenir:

  • le test de la boucle while pourrait lire le registre d'état une seule fois, puisque le compilateur pourrait supposer que tout ce qu'il a indiqué ne changerait jamais (il n'y a rien dans le test de la boucle while ou la boucle elle-même qui pourrait le changer). Si vous avez entré la fonction alors qu'il n'y avait aucun caractère en attente dans le matériel UART, vous pourriez vous retrouver dans une boucle infinie qui ne s'arrêtait jamais même lorsqu'un caractère était reçu.
  • la lecture du registre de réception pourrait être déplacée par le compilateur avant la boucle while - encore une fois parce qu'il n'y a rien dans la fonction qui indique que *recv_regla boucle est modifiée, il n'y a aucune raison pour laquelle il ne peut pas être lu avant d'entrer dans la boucle.

Les volatilequalificatifs garantissent que ces optimisations ne sont pas effectuées par le compilateur.

Michael Burr
la source
5
+1 pour l'explication. Et j'ai une question: qu'en est-il des méthodes volatiles const? Si j'ai une classe à laquelle de nombreux threads accèdent (bien que l'accès soit synchronisé avec le mutex), mes méthodes const doivent-elles également être volatiles (car certaines variables peuvent être modifiées par un autre thread)
Sasa
39
  • volatile dira au compilateur de ne pas optimiser le code lié à la variable, généralement quand on sait qu'elle peut être modifiée de "l'extérieur", par exemple par un autre thread.
  • const dira au compilateur qu'il est interdit au programme de modifier la valeur de la variable.
  • const volatileest une chose très spéciale que vous verrez probablement utilisée exactement 0 fois dans votre vie (tm). Comme on pouvait s'y attendre, cela signifie que le programme ne peut pas modifier la valeur de la variable, mais que la valeur peut être modifiée de l'extérieur, donc aucune optimisation ne sera effectuée sur la variable.
mingos
la source
12
J'aurais pensé que les volatilevariables sont généralement ce qui se passe lorsque vous commencez à jouer avec le matériel, pas avec d'autres threads. Là où j'ai vu const volatileutilisé, c'est dans des choses comme les registres d'état mappés en mémoire ou autres.
JUSTE MON OPINION correcte le
2
Bien sûr, vous avez tout à fait raison, le multithreading n'est qu'un exemple, mais pas le seul :).
mingos le
25
Si vous travaillez avec des systèmes embarqués, vous verrez cela très souvent.
Daniel Grillo du
28

Ce n'est pas parce que la variable est const qu'elle n'a peut-être pas changé entre deux points de séquence.

Constness est une promesse que vous faites de ne pas changer la valeur, pas que la valeur ne sera pas modifiée.

Alexandre C.
la source
9
Plus un pour souligner que les constdonnées ne sont pas «constantes».
Bogdan Alexandru
7

J'ai eu besoin de l'utiliser dans une application intégrée où certaines variables de configuration sont situées dans une zone de mémoire flash qui peut être mise à jour par un chargeur de démarrage. Ces variables de configuration sont `` constantes '' pendant l'exécution, mais sans le qualificatif volatile, le compilateur optimiserait quelque chose comme ça ...

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

... en précalculant la valeur de la constante et en utilisant une instruction d'assemblage immédiate, ou en chargeant la constante depuis un emplacement proche, de sorte que toute mise à jour de la valeur CANID d'origine dans la zone flash de configuration soit ignorée. CANID doit être const volatile.

push2eject
la source
7

En C, const et volatile sont des qualificatifs de type et ces deux sont indépendants.

Fondamentalement, const signifie que la valeur n'est pas modifiable par le programme.

Et volatile signifie que la valeur est sujette à un changement soudain (éventuellement de l'extérieur du programme).

En fait, le standard C mentionne un exemple de déclaration valide qui est à la fois constante et volatile. L'exemple est

"Extern const volatile int real_time_clock;"

où real_time_clock peut être modifiable par le matériel, mais ne peut pas être assigné, incrémenté ou décrémenté.

Nous devrions donc déjà traiter const et volatile séparément. En outre, ces qualificatifs de type s'appliquent également à struct, union, enum et typedef.

user2903536
la source
5

Vous pouvez utiliser const et volatile ensemble. Par exemple, si 0x30 est supposé être la valeur d'un port qui est modifié uniquement par des conditions externes, la déclaration suivante empêcherait toute possibilité d'effets secondaires accidentels:

const volatile char *port = (const volatile char *)0x30;
Étape
la source
4

constsignifie que la variable ne peut pas être modifiée par le code c, pas qu'elle ne peut pas changer. Cela signifie qu'aucune instruction ne peut écrire dans la variable, mais sa valeur peut encore changer.

volatilesignifie que la variable peut changer à tout moment et qu'aucune valeur mise en cache ne peut donc être utilisée; chaque accès à la variable doit être exécuté à son adresse mémoire.

Puisque la question est étiquetée "intégrée" et en supposant temp s'agit d'une variable déclarée par l'utilisateur et non d'un registre lié au matériel (puisque ceux-ci sont généralement traités dans un fichier .h séparé), considérez:

Processeur intégré qui possède à la fois une mémoire de données volatile en lecture-écriture (RAM) et une mémoire de données non volatile en lecture seule, par exemple une mémoire FLASH dans l'architecture von-Neumann, où les données et l'espace de programme partagent un bus de données et d'adresses commun.

Si vous déclarez const temp avoir une valeur (au moins si différente de 0), le compilateur affectera la variable à une adresse dans l'espace FLASH, car même si elle était affectée à une adresse RAM, il a encore besoin de mémoire FLASH pour stocker la valeur initiale de la variable, faisant de l'adresse RAM une perte d'espace puisque toutes les opérations sont en lecture seule.

En conséquence:

int temp;est une variable stockée dans la RAM, initialisée à 0 au démarrage (cstart), les valeurs mises en cache peuvent être utilisées.

const int temp;est une variable stockée dans (en lecture seule) FLASH, initialisée à 0 au moment du compilateur, les valeurs mises en cache peuvent être utilisées.

volatile int temp; est une variable stockée dans la RAM, initialisée à 0 au démarrage (cstart), les valeurs mises en cache ne seront PAS utilisées.

const volatile int temp; est une variable stockée dans (en lecture seule) FLASH, initialisée à 0 au moment du compilateur, les valeurs mises en cache ne seront PAS utilisées

Voici la partie utile:

De nos jours, la plupart des processeurs embarqués ont la possibilité d'apporter des modifications à leur mémoire non volatile en lecture seule au moyen d'un module de fonction spécial, auquel cas const int temppeuvent être modifiés au moment de l'exécution, mais pas directement. Dit d'une autre manière, une fonction peut modifier la valeur à l'adresse oùtemp est stockée.

Un exemple pratique serait d'utiliser temppour le numéro de série de l'appareil. La première fois que le processeur embarqué s'exécute, tempsera égal à 0 (ou à la valeur déclarée) et une fonction peut utiliser ce fait pour exécuter un test pendant la production et en cas de succès, demander à se voir attribuer un numéro de série et modifier la valeur detemp par des moyens d'une fonction spéciale. Certains processeurs ont une plage d'adresses spéciale avec une mémoire OTP (programmable une fois) juste pour cela.

Mais voici la différence:

S'il const int temps'agit d'un identifiant modifiable au lieu d'un numéro de série programmable à volatileusage unique et n'est PAS déclaré , une valeur mise en cache peut être utilisée jusqu'au prochain démarrage, ce qui signifie que le nouvel identifiant peut ne pas être valide jusqu'au prochain redémarrage, ou pire encore, certaines fonctions peut utiliser la nouvelle valeur tandis que d'autres peuvent utiliser une ancienne valeur mise en cache jusqu'au redémarrage. Si const int tempIS déclaré voltaile, le changement d'identifiant prendra effet immédiatement.

Michael Kusch
la source
Wow, cette réponse est longue
2

En termes simples, la valeur de la variable «const volatile» ne peut pas être modifiée par programme mais peut être modifiée par le matériel. Volatile ici est d'empêcher toute optimisation du compilateur.

Rajeshsam
la source
1

Nous utilisons le mot clé «const» pour une variable lorsque nous ne voulons pas que le programme la modifie. Alors que lorsque nous déclarons une variable «const volatile», nous disons au programme de ne pas la modifier et au compilateur que cette variable peut être modifiée de manière inattendue à partir d'une entrée provenant du monde extérieur.

Ali
la source