Si nous déclarons une variable sous la forme volatile
à chaque fois que la nouvelle valeur est mise à jour
Si nous déclarons une variable sous la forme const
, sa valeur ne sera pas modifiée
Ensuite 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 objet marqué comme const volatile
ne sera pas autorisé à être modifié par le code (une erreur sera générée en raison du qualificatif const
) - au moins par le biais de ce nom/pointeur particulier.
La partie volatile
du qualificatif signifie que le compilateur ne peut pas optimiser ou réorganiser l'accès à l'objet.
Dans un système intégré, cela est généralement utilisé pour accéder aux registres du matériel qui peuvent être lus et mis à jour par le matériel, mais cela n'a aucun sens d'écrire dans (ou pourrait être une erreur dans laquelle écrire).
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 donner une valeur différente en fonction des événements survenus 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 ' Ne pas vous parler des changements d’é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
, plusieurs problèmes pourraient survenir:
*recv_reg
est modifié par la boucle, il n’ya aucune raison qu’il ne puisse pas être lu avant d’entrer dans la boucle.Les qualificateurs volatile
garantissent que ces optimisations ne sont pas effectuées par le compilateur.
volatile
indiquera au compilateur de ne pas optimiser le code associé à la variable, généralement lorsque nous savons qu'il peut être modifié "de l'extérieur", par exemple. par un autre fil.const
dira 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 (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. Par conséquent, aucune optimisation ne sera effectuée sur la variable.Ce n'est pas parce que la variable est constante qu'il peut ne pas avoir 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 changée.
J'ai eu besoin de l'utiliser dans une application intégrée dans laquelle certaines variables de configuration sont situées 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 optimiserait quelque chose comme ceci ...
cantx.id = 0x10<<24 | CANID<<12 | 0;
... en calculant à l'avance 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 de configuration de configuration soit ignorée. CANID doit être constant.
En C, const et volatile sont des qualificatifs de type et ces deux sont indépendants.
En gros, const signifie que la valeur n’est pas modifiable par le programme.
Et volatile signifie que la valeur est sujette à des changements soudains (éventuellement en dehors du programme).
En fait, le standard C mentionne un exemple de déclaration valide qui est à la fois constant et volatile. L'exemple est
"Extern constante volatile int real_time_clock;"
où real_time_clock peut être modifiable par le matériel, mais ne peut pas être attribué, incrémenté ou décrémenté.
Donc, nous devrions déjà traiter const et volatile séparément. En outre, ces qualificatifs de type s'appliquent également à struct, union, enum et typedef.
Cet article décrit les scénarios dans lesquels vous souhaitez combiner des qualificatifs constants et volatils.
http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/
const
signifie que la variable ne peut pas être modifiée par le code c, pas qu'elle ne puisse pas changer. Cela signifie qu'aucune instruction ne peut écrire dans la variable, mais que sa valeur peut encore changer.
volatile
signifie que la variable peut changer à tout moment et qu'aucune valeur en cache ne peut être utilisée; chaque accès à la variable doit être exécuté à son adresse mémoire.
Puisque la question est étiquetée "incorporée" et supposons que temp
soit une variable déclarée par l'utilisateur, et non un registre lié au matériel (car elles sont généralement traitées dans un fichier .h séparé), considérons:
Processeur intégré possédant à la fois une mémoire RAM volatile (RAM) et une mémoire RAM non volatile en lecture seule, par exemple une mémoire FLASH dans une architecture de von Neumann, où les données et l’espace de programme partagent un bus de données et d’adresse commun.
Si vous déclarez const temp
pour avoir une valeur (au moins si différente de 0), le compilateur assignera la variable à une adresse dans l’espace FLASH, car même si elle était affectée à une RAM adresse, elle reste nécessite de la mémoire FLASH pour stocker la valeur initiale de la variable, l’adresse RAM) étant une perte d’espace, car 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 en cache peuvent être utilisées.
const int temp;
_ est une variable stockée dans (lecture continue) FLASH, initialisée à 0 au moment de la compilation, les valeurs 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 en cache NE seront PAS utilisées.
const volatile int temp;
est une variable stockée dans (lecture continue) FLASH, initialisée à 0 au moment de la compilation, les valeurs 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, mais pas directement. En d'autres termes, une fonction peut modifier la valeur à l'adresse où est stocké temp
.
Un exemple pratique consisterait à utiliser temp
comme numéro de série du périphérique. Lors de la première exécution du processeur intégré, temp
sera égal à 0 (ou à la valeur déclarée) et une fonction peut utiliser ce fait pour exécuter un test en production et, le cas échéant, demander à se voir attribuer 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 fois) rien que pour cela.
Mais voici la différence:
Si const int temp
est un ID modifiable au lieu d'un numéro de série programmable une 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 ID peut ne pas être valide jusqu'au prochain redémarrage. , ou pire encore, certaines fonctions peuvent utiliser la nouvelle valeur, d’autres jusqu’à utiliser une ancienne valeur en cache jusqu’au redémarrage. Si const int temp
IS déclarée voltaile
, le changement d’ID entre en vigueur immédiatement.
Vous pouvez utiliser const et volatile ensemble. Par exemple, si 0x30 est supposé être la valeur d'un port modifié uniquement par des conditions externes, 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 la change. Tandis que lorsque nous déclarons une variable 'constante de volatile', nous disons au programme de ne pas la changer et au compilateur que cette variable peut être modifiée de manière inattendue à partir d'une entrée provenant du monde extérieur.
En termes simples, la valeur de la variable 'const volatile' ne peut pas être modifiée par programme mais par le matériel. Volatile est d'empêcher toute optimisation du compilateur.