Différence entre const & const volatile

Si nous déclarons une variable aussi volatile chaque fois que la nouvelle valeur est mise à jour
Si nous déclarons une variable comme const la valeur de cette variable ne sera pas modifiée

Alors const volatile int temp;
A quoi sert de déclarer la variable temp comme ci-dessus?
Que se passe-t-il si nous déclarons comme const int temp ?

Un object marqué comme const volatile ne sera pas autorisé à être modifié par le code (une erreur sera déclenchée à cause du qualificateur const ) – au moins via ce nom / pointeur particulier.

La partie volatile du qualificatif signifie que le compilateur ne peut pas optimiser ou réorganiser l’access à l’object.

Dans un système intégré, il est généralement utilisé pour accéder à des registres matériels pouvant être lus et mis à jour par le matériel, mais cela n’a aucun sens d’écrire (ou peut-être une erreur d’écriture).

Un exemple pourrait être le registre d’état d’un port série. Différents bits indiqueront si un caractère est en attente de lecture ou si le registre de transmission est prêt à accepter un nouveau caractère (c’est-à-dire qu’il est vide). Chaque lecture de ce registre d’état peut entraîner une valeur différente selon ce qui s’est passé 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 parler des changements de 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 boucle while peut lire le registre d’état une seule fois, car le compilateur peut supposer que tout ce qu’il indique ne changera jamais (il n’y a rien dans le test ou la boucle while 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’est jamais arrêtée même lorsqu’un caractère a été 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_reg est modifié par la boucle, il n’y a aucune raison pour qu’elle ne soit pas lue avant d’entrer dans la boucle.

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

  • volatile va dire au compilateur de ne pas optimiser le code lié à la variable, généralement quand on sait qu’il peut être changé de “extérieur”, par exemple par un autre thread.
  • const indiquera au compilateur qu’il est interdit au programme de modifier la valeur de la variable.
  • const volatile est une chose très spéciale que vous verrez probablement utilisée exactement 0 fois dans votre vie ™. Comme on peut 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.

Ce n’est pas parce que la variable est const qu’elle n’a pas changé entre deux points de séquence.

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

J’ai eu besoin de l’utiliser dans une application intégrée où certaines variables de configuration se trouvent dans une zone de mémoire flash pouvant ê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 optimise quelque chose comme ça …

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

... en pré-calculant la valeur 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 de configuration flash soit ignorée. CANID doit être constable.

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 en dehors du programme).

En fait, le standard C mentionne un exemple de déclaration valide à la fois const 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 atsortingbué, incrémenté ou décrémenté.

Nous devrions donc déjà traiter les const et les volatiles séparément. De plus, ces qualificatifs de type s’appliquent également à struct, union, enum et typedef.

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

volatile signifie que la variable peut changer à tout moment et donc aucune valeur mise en cache ne peut être utilisée; chaque access à la variable doit être exécuté sur son adresse mémoire.

Étant donné que la question est balisée “incorporée” et que temp est une variable déclarée par l’utilisateur, et non un registre lié au matériel (puisque ces variables sont généralement traitées dans un fichier .h distinct), considérez:

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

Si vous déclarez const temp pour 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 assignée à une adresse RAM, elle a toujours besoin de mémoire FLASH pour stocker le valeur initiale de la variable, ce qui rend l’adresse de la 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 (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 FLASH (lecture seule), 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 temp peut être modifié à l’exécution, pas directement. Autrement dit, une fonction peut modifier la valeur à l’adresse où temp est stocké.

Un exemple pratique serait d’utiliser temp pour le numéro de série de l’appareil. La première fois que le processeur intégré s’exécute, temp sera égal à 0 (ou la valeur déclarée) et une fonction peut utiliser ce fait pour exécuter un test pendant la production et, si elle réussit, demander à recevoir un numéro de série et modifier la valeur de temp au moyen d’une fonction spéciale. Certains processeurs ont une plage d’adresses spéciale avec une mémoire OTP (programmable une seule fois) juste pour cela.

Mais voici la différence:

Si const int temp est un identifiant modifiable au lieu d’un numéro de série programmable une seule fois et n’est PAS déclaré volatile , 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 au prochain redémarrage, voire Pire encore, certaines fonctions peuvent utiliser la nouvelle valeur alors que d’autres peuvent utiliser une ancienne valeur mise en cache avant le redémarrage. Si const int temp est déclaré voltaile , la modification de l’ID prendra effet immédiatement.

Cet article décrit les scénarios dans lesquels vous souhaitez combiner des qualificateurs const et volatiles.

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

Vous pouvez utiliser const et volatile ensemble. Par exemple, si on suppose que 0x30 est la valeur d’un port modifié par des conditions externes uniquement, la déclaration suivante éviterait toute possibilité d’effets secondaires accidentels:

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

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

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 pour empêcher toute optimisation du compilateur.