Namespaces
Variants

volatile type qualifier

From cppreference.net

Chaque type individuel dans le système de types du C possède plusieurs versions qualifiées de ce type, correspondant à un, deux ou l'ensemble des trois qualificateurs const , volatile , et, pour les pointeurs vers des types objet, restrict . Cette page décrit les effets du qualificateur volatile .

Chaque accès (en lecture et en écriture) effectué via une expression lvalue de type qualifié volatile est considéré comme un effet secondaire observable à des fins d'optimisation et est évalué strictement selon les règles de la machine abstraite (c'est-à-dire que toutes les écritures sont terminées à un moment donné avant le point de séquence suivant). Cela signifie qu'au sein d'un seul thread d'exécution, un accès volatile ne peut pas être optimisé ou réordonné par rapport à un autre effet secondaire visible qui est séparé par un point de séquence de l'accès volatile.

Une conversion d'une valeur non volatile en un type volatile n'a aucun effet. Pour accéder à un objet non volatile en utilisant une sémantique volatile, son adresse doit être convertie en un pointeur-vers-volatile, puis l'accès doit être effectué via ce pointeur.

Toute tentative de lecture ou d'écriture d'un objet dont le type est qualifié volatile via une lvalue non volatile entraîne un comportement indéfini :

volatile int n = 1; // objet de type qualifié volatile
int* p = (int*)&n;
int val = *p; // comportement indéfini

Un membre d'une structure ou d'un type union qualifié volatile acquiert la qualification du type auquel il appartient (à la fois lorsqu'il est accédé en utilisant l'opérateur . ou l'opérateur -> ):

struct s { int i; const int ci; } s;
// le type de s.i est int, le type de s.ci est const int
volatile struct s vs;
// les types de vs.i et vs.ci sont volatile int et const volatile int

Si un type tableau est déclaré avec le qualificatif de type volatile (via l'utilisation de typedef ), le type tableau n'est pas qualifié volatile, mais son type d'élément l'est.

(jusqu'à C23)

Un type tableau et son type d'élément sont toujours considérés comme étant identiquement qualifiés volatile.

(depuis C23)
typedef int A[2][3];
volatile A a = {{4, 5, 6}, {7, 8, 9}}; // tableau de tableau de volatile int
int* pi = a[0]; // Erreur : a[0] a le type volatile int*
void *unqual_ptr = a; // OK jusqu'à C23 ; erreur depuis C23
// Notes : clang applique la règle en C++/C23 même dans les modes C89-C17

Si un type de fonction est déclaré avec le qualificatif de type volatile (via l'utilisation d'un typedef ), le comportement est indéfini.

Dans une déclaration de fonction, le mot-clé volatile peut apparaître à l'intérieur des crochets utilisés pour déclarer un type tableau d'un paramètre de fonction. Il qualifie le type pointeur vers lequel le type tableau est transformé.

Les deux déclarations suivantes déclarent la même fonction :

void f(double x[volatile], const double y[volatile]);
void f(double * volatile x, const double * volatile y);
(depuis C99)

Un pointeur vers un type non volatile peut être implicitement converti en un pointeur vers la version qualifiée volatile du même type ou compatible . La conversion inverse nécessite une expression de cast.

int* p = 0;
volatile int* vp = p; // OK : ajoute des qualificateurs (int vers volatile int)
p = vp; // Erreur : supprime des qualificateurs (volatile int vers int)
p = (int*)vp; // OK : cast

Notez qu'un pointeur vers un pointeur vers T n'est pas convertible en pointeur vers un pointeur vers volatile T ; pour que deux types soient compatibles, leurs qualifications doivent être identiques :

char *p = 0;
volatile char **vpp = &p; // Erreur : char* et volatile char* ne sont pas des types compatibles
char * volatile *pvp = &p; // OK, ajoute les qualificateurs (char* vers char*volatile)

Table des matières

Utilisations de volatile

1) static volatile les objets modélisent les ports d'E/S mappés en mémoire, et static const volatile les objets modélisent les ports d'entrée mappés en mémoire, tels qu'une horloge temps réel :
volatile short *ttyport = (volatile short*)TTYPORT_ADDR;
for(int i = 0; i < N; ++i)
    *ttyport = a[i]; // *ttyport is an lvalue of type volatile short
2) static volatile objets de type sig_atomic_t sont utilisés pour la communication avec les gestionnaires de signaux .
3) volatile Les variables volatile qui sont locales à une fonction contenant un appel de la macro setjmp sont les seules variables locales garanties de conserver leurs valeurs après le retour de longjmp .
4) De plus, les variables volatiles peuvent être utilisées pour désactiver certaines formes d'optimisation, par exemple pour désactiver l'élimination des stockages morts ou le pliage constant pour les micro-benchmarks.

Notez que les variables volatiles ne conviennent pas à la communication entre threads ; elles n'offrent pas l'atomicité, la synchronisation ou l'ordonnancement de la mémoire. Une lecture d'une variable volatile qui est modifiée par un autre thread sans synchronisation ou une modification concurrente par deux threads non synchronisés est un comportement indéfini en raison d'une course aux données.

Mots-clés

volatile

Exemple

démontre l'utilisation de volatile pour désactiver les optimisations

#include <stdio.h>
#include <time.h>
int main(void)
{
    clock_t t = clock();
    double d = 0.0;
    for (int n = 0; n < 10000; ++n)
        for (int m = 0; m < 10000; ++m)
            d += d * n * m; // reads from and writes to a non-volatile 
    printf("Modified a non-volatile variable 100m times. "
           "Time used: %.2f seconds\n",
           (double)(clock() - t)/CLOCKS_PER_SEC);
    t = clock();
    volatile double vd = 0.0;
    for (int n = 0; n < 10000; ++n)
        for (int m = 0; m < 10000; ++m) {
            double prod = vd * n * m; // reads from a volatile
            vd += prod; // reads from and writes to a volatile
        } 
    printf("Modified a volatile variable 100m times. "
           "Time used: %.2f seconds\n",
           (double)(clock() - t)/CLOCKS_PER_SEC);
}

Sortie possible :

Modified a non-volatile variable 100m times. Time used: 0.00 seconds
Modified a volatile variable 100m times. Time used: 0.79 seconds

Références

  • Norme C17 (ISO/IEC 9899:2018):
  • 6.7.3 Qualificateurs de type (p: 87-90)
  • Norme C11 (ISO/CEI 9899:2011) :
  • 6.7.3 Qualificateurs de type (p: 121-123)
  • Norme C99 (ISO/IEC 9899:1999) :
  • 6.7.3 Qualificateurs de type (p: 108-110)
  • Norme C89/C90 (ISO/IEC 9899:1990) :
  • 6.5.3 Qualificateurs de type

Voir aussi

Documentation C++ pour les qualificateurs de type cv ( const et volatile )