Puntero declarado como constante y volátil
volatile (6)
Mientras leía me encontré con este tipo de declaración y la siguiente línea:
const volatile char *p=(const volatile char *) 0x30;
El valor de p se cambia solo por condiciones externas
No entiendo cuáles son las condiciones externas. ¿Y también cuál es el uso práctico de este tipo de declaración ?
Considere un registro de hardware de solo lectura, por ejemplo, de su tarjeta de red.
Puede cambiar fuera del control del programa, por lo que el compilador no puede almacenar en caché su valor en un registro ni optimizarlo.
Por lo tanto,
volatile
.
Y es de solo lectura, por lo que no debe escribirle.
Por lo tanto,
const
.
El
const
dice que el flujo de su programa no va a modificar lo que señala
p
.
Cualquier intento de modificar el valor después de desreferenciar el puntero dará como resultado un error en tiempo de compilación:
*p = ''A''; // will not compile
Tenga en cuenta que este no es un contrato particularmente fuerte;
el valor en la ubicación
0x30
todavía se puede cambiar a través de un puntero no constante con alias, que no sea
p
:
volatile char *q = 0x30;
*q = ''A''; // will compile
Otra forma de romper este contrato es desechando la
const
de
p
:
*(volatile char *) p = ''A''; // will compile
Sin embargo, el
volatile
no excluye ninguna modificación que pueda ser causada por otro subproceso, el núcleo, un controlador de señal asíncrono o un dispositivo externo que tenga acceso al mismo espacio de memoria.
De esta manera, el compilador no puede asumir erróneamente que el valor señalado por
p
no cambia y lo cargará de la memoria cada vez que se haga referencia a él:
/*
The character at 0x30 will be read on every iteration,
even if the compiler has proven that the program itself
doesn''t modify the value at that address.
*/
while (*p) {
...
}
Si el compilador optimizara erróneamente tal construcción, podría emitir instrucciones que cargan el valor solo una vez desde la memoria y luego lo mantienen en un registro. El registro es esencialmente una copia independiente y cualquier cambio en la ubicación original no se reflejará allí, y no hace falta decir que esto puede causar algunos errores muy desagradables.
Podemos usar el artículo Introducción a la palabra clave volátil que dice:
Una variable debe declararse volátil siempre que su valor pueda cambiar inesperadamente. En la práctica, solo tres tipos de variables podrían cambiar:
- Registros periféricos mapeados en memoria
- Variables globales modificadas por una rutina de servicio de interrupción
- Variables globales dentro de una aplicación multiproceso
y:
Los sistemas integrados contienen hardware real, generalmente con periféricos sofisticados. Estos periféricos contienen registros cuyos valores pueden cambiar de forma asíncrona al flujo del programa. Como un ejemplo muy simple, considere un registro de estado de 8 bits en la dirección 0x1234. Es necesario que sondee el registro de estado hasta que no sea cero. La nave y la implementación incorrecta son las siguientes:
UINT1 * ptr = (UINT1 *) 0x1234; // Wait for register to become non-zero. while (*ptr == 0); // Do something else.
Es casi seguro que fallará tan pronto como encienda el optimizador, ya que el compilador generará un lenguaje ensamblador similar a este:
mov ptr, #0x1234 mov a, @ptr loop bz loop
El const dice que su programa no cambiará la variable, pero como se señaló en el artículo, fuentes externas podrían y volátil evita que se optimice.
Primero, permítanme citar el ejemplo del estándar
C11
, capítulo §6.7.3,
calificadores de tipo
Un objeto declarado
extern const volatile int real_time_clock;
puede ser modificable por hardware, pero no puede asignarse, incrementarse o disminuirse.
También, nota al pie relacionada (134),
Se puede usar una declaración volátil para describir un objeto correspondiente a un puerto de entrada / salida mapeado en memoria o un objeto al que se accede mediante una función de interrupción asíncrona. Las acciones en los objetos así declarados no deben ser "optimizadas" por una implementación o reordenarse, excepto según lo permitido por las reglas para evaluar expresiones.
Eso significa que el valor de la variable puede ser modificado por el hardware (a través de la asignación de memoria), pero no puede modificarse "programáticamente".
Entonces, la ventaja es doble aquí,
- El valor siempre que se use se leerá de la memoria (no se permite el almacenamiento en caché), lo que le proporcionará el último valor actualizado (si está actualizado).
- El valor no puede ser alterado ( sobreescrito ) intencionalmente o no por el programa.
const
no hace una variable constante.
Simplemente hace que el compilador rechace algún acceso de escritura.
Todavía es posible escribir en la variable (a través de punteros const-casted, por ejemplo).
Puede ver la
const
como una protección contra errores de codificación.
Esta declaración se asegura de no escribir inadvertidamente en
p
, mientras le dice al compilador que no optimice los accesos (caché, ejecución fuera de orden (?), ...) porque un evento externo puede escribir en
p
.
* const volátil char * p = (const volátil char
) 0x30;
Qué se entiende por:
El valor de p se cambia solo por condiciones externas.
Conceptualmente, puede pensar en este tipo de variable como un visor lógico . Similar en concepto a la mirilla en una puerta. Una mirilla le permite ver lo que está del otro lado de la puerta, pero no le permite cambiar lo que está del otro lado ( const ). Sin embargo, las condiciones en el exterior de la puerta pueden cambiar por su propia voluntad (son volátiles ). Puede ver lo que sucede, pero no puede cambiar lo que sucede.
En un sistema embebido, por ejemplo, hay registros de hardware diseñados para proporcionar información de estado sobre eventos que suceden en el mundo exterior. Un codificador óptico, por ejemplo, utilizado para detectar RPM establecerá un valor en un registro. Cada rotación, detecta la luz de un led y modifica el valor en un registro de hardware. Esto es lo que se entiende por condiciones externas . En el otro lado de la imagen, es decir, en su código (quizás un bucle de control PID), puede leer esta información para proporcionar ajustes en el bucle, pero no puede cambiar este valor, ni desearía hacerlo. ( const )
Desde la perspectiva de su software, esto ilustra: