c++ - software - ¿Puede un puntero ser volátil?
software volatile (6)
Considere el siguiente código:
int square(volatile int *p)
{
return *p * *p;
}
Ahora, la palabra clave volatile
indica que el valor en una ubicación de memoria se puede alterar de maneras desconocidas para el compilador o tener otros efectos secundarios desconocidos (por ejemplo, modificación a través de una interrupción de señal, registro de hardware o I / O mapeada en memoria) aunque no haya nada en El código del programa modifica los contenidos.
Entonces, ¿qué sucede exactamente cuando declaramos un puntero como volátil?
¿Funcionará el código mencionado anteriormente, o es diferente de esto?
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
¿Podemos terminar multiplicando números diferentes, ya que los punteros son volátiles?
¿O hay una mejor manera de hacerlo?
¿Puede un puntero ser
volatile
?
Absolutamente; Cualquier tipo, excluyendo funciones y referencias, puede ser volatile
calificado.
Tenga en cuenta que un puntero volátil se declara como T *volatile
, no volatile T*
, que en su lugar declara un puntero a volátil .
Un puntero volátil significa que el valor del puntero, es decir, su dirección y no el valor apuntado por, puede tener efectos secundarios que no son visibles para el compilador cuando se accede a ellos; por lo tanto, las optimizaciones derivadas de la "regla de if-if" no pueden tomarse en cuenta para esos accesos.
int square(volatile int *p) { return *p * *p; }
El compilador no puede asumir que la lectura *p
obtiene el mismo valor, por lo que no se permite el almacenamiento en caché de su valor en una variable. Como dices, el resultado puede variar y no ser el cuadrado de *p
.
Ejemplo concreto: digamos que tienes dos arrays de int
s
int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };
y un puntero a uno de ellos.
int * /*volatile*/ p = a1;
Con alguna operación sobre los elementos puntiagudos.
for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i)
*(p + i) *= 2;
aquí p
debe leerse cada iteración si la hace volatile
porque, quizás, en realidad puede apuntar a a2
debido a eventos externos.
La palabra clave volatile
es una sugerencia para el compilador (7.1.6.1/7):
Nota: volatile es una sugerencia para la implementación para evitar una optimización agresiva que involucre al objeto, ya que el valor del objeto podría cambiarse de manera indetectable por una implementación. Además, para algunas implementaciones, la volatilidad puede indicar que se requieren instrucciones especiales de hardware para acceder al objeto. Ver 1.9 para semántica detallada. En general, se pretende que la semántica de volatile sea la misma en C ++ que en C. - nota final]
Qué significa eso? Bueno, mira este código:
bool condition = false;
while(!condition)
{
...
}
de forma predeterminada, el compilador optimizará fácilmente la condición (no cambia, por lo que no es necesario comprobarlo en cada iteración). Sin embargo, si declara la condición como volatile
, no se realizará la optimización.
Por supuesto, puede tener un puntero volátil y es posible escribir código que se bloquee debido a eso, pero el hecho de que una variable sea volative
no significa que necesariamente se vaya a cambiar debido a alguna interferencia externa.
Puede que termines multiplicando números diferentes porque es volátil y podría cambiarse inesperadamente. Entonces, puedes probar algo como esto:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
Sí, claro que puedes tener un puntero volátil.
Volatile significa nada más ni nada menos que cada acceso en el objeto volátil (de cualquier tipo) se trata como un efecto secundario visible, y por lo tanto está exento de optimización (en particular, esto significa que los accesos no se pueden reordenar o colapsar o optimizado todo en conjunto). Eso es cierto para leer o escribir un valor, para llamar a funciones de miembro y, por supuesto, para desreferenciar, también.
Tenga en cuenta que cuando el párrafo anterior dice "reordenación", se asume un solo hilo de ejecución . La volatilidad no es un sustituto de las operaciones atómicas o mutexes / bloqueos.
En palabras más simples, volatile
generalmente se traduce en aproximadamente "No optimizar, simplemente haga exactamente lo que le digo".
En el contexto de un puntero , consulte el patrón de uso ejemplar dado por el conocido artículo "Lo que todo programador debe saber sobre el comportamiento indebido" de Chris Lattner (sí, ese artículo es sobre C, no sobre C ++, pero se aplica lo mismo):
Si está utilizando un compilador basado en LLVM, puede eliminar la referencia de un puntero nulo "volátil" para obtener una falla si eso es lo que está buscando, ya que las cargas y las tiendas volátiles generalmente no son tocadas por el optimizador.
Sí, un puntero puede ser volátil si la variable a la que apunta puede cambiar inesperadamente aunque el código no resulte evidente en cómo podría suceder esto.
Un ejemplo es un objeto que puede ser modificado por algo que es externo al hilo controlador y que el compilador no debe optimizar.
El lugar más probable para usar el especificador volátil es el código de bajo nivel que trata directamente con el hardware y donde pueden ocurrir cambios inesperados.
Sí. int * volatile
En C ++, las palabras clave de acuerdo con el tipo / puntero / referencia van después del token, como int * const
es un puntero constante a entero, int const *
es un puntero a entero constante, int const * const
es un puntero constante a entero constante etc. Puede escribir una palabra clave antes del tipo solo si es para el primer token: const int x
es igual a int const x
.