Namespaces
Variants

volatile type qualifier

From cppreference.net

Cada tipo individual en el sistema de tipos de C tiene varias versiones calificadas de ese tipo, correspondientes a uno, dos, o los tres calificadores: const , volatile , y, para punteros a tipos objeto, restrict . Esta página describe los efectos del calificador volatile .

Cada acceso (tanto lectura como escritura) realizado a través de una expresión lvalue de tipo calificado como volátil se considera un efecto secundario observable para fines de optimización y se evalúa estrictamente de acuerdo con las reglas de la máquina abstracta (es decir, todas las escrituras se completan en algún momento antes del siguiente punto de secuencia). Esto significa que dentro de un único hilo de ejecución, un acceso volátil no puede ser optimizado eliminado o reordenado en relación con otro efecto secundario visible que esté separado por un punto de secuencia del acceso volátil.

Una conversión de un valor no volátil a un tipo volátil no tiene efecto. Para acceder a un objeto no volátil utilizando semántica volátil, su dirección debe convertirse a un puntero-a-volátil y luego el acceso debe realizarse a través de ese puntero.

Cualquier intento de leer o escribir en un objeto cuyo tipo está calificado como volatile a través de un lvalue no volatile resulta en comportamiento indefinido:

volatile int n = 1; // objeto de tipo calificado como volátil
int* p = (int*)&n;
int val = *p; // comportamiento indefinido

Un miembro de una estructura o unión calificada como volátil adquiere la calificación del tipo al que pertenece (tanto cuando se accede usando el . operador como el -> operador):

struct s { int i; const int ci; } s;
// el tipo de s.i es int, el tipo de s.ci es const int
volatile struct s vs;
// los tipos de vs.i y vs.ci son volatile int y const volatile int

Si un tipo de array se declara con el calificador de tipo volatile (mediante el uso de typedef ), el tipo de array no está calificado como volatile, pero su tipo de elemento sí lo está.

(until C23)

Un tipo de array y su tipo de elemento siempre se consideran idénticamente calificados como volatile.

(since C23)
typedef int A[2][3];
volatile A a = {{4, 5, 6}, {7, 8, 9}}; // arreglo de arreglo de volatile int
int* pi = a[0]; // Error: a[0] tiene tipo volatile int*
void *unqual_ptr = a; // OK hasta C23; error desde C23
// Notas: clang aplica la regla en C++/C23 incluso en modos C89-C17

Si un tipo de función se declara con el calificador de tipo volatile (mediante el uso de typedef ), el comportamiento es indefinido.

En una declaración de función, la palabra clave volatile puede aparecer dentro de los corchetes utilizados para declarar un tipo de arreglo de un parámetro de función. Califica el tipo de puntero al cual se transforma el tipo de arreglo.

Las siguientes dos declaraciones declaran la misma función:

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

Un puntero a un tipo no volátil puede convertirse implícitamente a un puntero a la versión calificada como volátil del mismo tipo o de un tipo compatible . La conversión inversa requiere una expresión de conversión explícita (cast).

int* p = 0;
volatile int* vp = p; // OK: agrega calificadores (int a volatile int)
p = vp; // Error: descarta calificadores (volatile int a int)
p = (int*)vp; // OK: conversión

Tenga en cuenta que un puntero a puntero a T no es convertible a un puntero a puntero a volatile T ; para que dos tipos sean compatibles, sus calificaciones deben ser idénticas:

char *p = 0;
volatile char **vpp = &p; // Error: char* y volatile char* no son tipos compatibles
char * volatile *pvp = &p; // OK, agrega calificadores (char* a char*volatile)

Contenidos

Usos de volatile

1) static volatile los objetos modelan puertos de E/S mapeados en memoria, y static const volatile los objetos modelan puertos de entrada mapeados en memoria, como un reloj en tiempo real:
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 objetos de tipo sig_atomic_t se utilizan para comunicación con signal handlers.
3) volatile Las variables que son locales a una función que contiene una invocación de la macro setjmp son las únicas variables locales garantizadas para conservar sus valores después de que longjmp retorne.
4) Además, las variables volátiles pueden utilizarse para deshabilitar ciertas formas de optimización, por ejemplo, para desactivar la eliminación de almacenamientos muertos o el plegado constante en micro-benchmarks.

Tenga en cuenta que las variables volátiles no son adecuadas para la comunicación entre hilos; no ofrecen atomicidad, sincronización u ordenamiento de memoria. Una lectura de una variable volátil que es modificada por otro hilo sin sincronización o modificación concurrente desde dos hilos no sincronizados es comportamiento indefinido debido a una carrera de datos.

Palabras clave

volatile

Ejemplo

demuestra el uso de volatile para deshabilitar optimizaciones

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

Salida posible:

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

Referencias

  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.7.3 Calificadores de tipo (p: 87-90)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.7.3 Calificadores de tipo (p: 121-123)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.7.3 Calificadores de tipo (p: 108-110)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 6.5.3 Calificadores de tipo

Véase también

Documentación de C++ para calificadores de tipo cv ( const y volatile )