Diferencia entre const y const volátil

89

Si declaramos una variable como volatilecada vez que se actualiza el valor nuevo
Si declaramos una variable como, constentonces el valor de esa variable no cambiará

Entonces, const volatile int temp;
¿de qué sirve declarar la variable tempcomo se indicó anteriormente?
¿Qué pasa si declaramos como const int temp?

usuario559208
fuente
No lo usaría const volatile int temp;en el alcance del bloque (es decir, dentro { }), no tiene uso allí.
MM

Respuestas:

145

Un objeto marcado como const volatileno podrá ser modificado por el código (se generará un error debido al constcalificador), al menos a través de ese nombre / puntero en particular.

La volatileparte del calificador significa que el compilador no puede optimizar ni reordenar el acceso al objeto.

En un sistema integrado, esto se usa normalmente para acceder a registros de hardware que el hardware puede leer y actualizar, pero no tiene sentido escribir en ellos (o podría ser un error escribir en ellos).

Un ejemplo podría ser el registro de estado de un puerto serie. Varios bits indicarán si un carácter está esperando ser leído o si el registro de transmisión está listo para aceptar un nuevo carácter (es decir, está vacío). Cada lectura de este registro de estado podría resultar en un valor diferente dependiendo de lo que haya ocurrido en el hardware del puerto serie.

No tiene sentido escribir en el registro de estado (dependiendo de la especificación de hardware en particular), pero debe asegurarse de que cada lectura del registro dé como resultado una lectura real del hardware, utilizando un valor en caché de una lectura anterior. Informarle sobre cambios en el estado del hardware.

Un ejemplo rápido:

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 estos punteros no se marcaron como siendo volatile, podrían surgir algunos problemas:

  • la prueba del ciclo while podría leer el registro de estado solo una vez, ya que el compilador podría asumir que lo que sea que apunte nunca cambiaría (no hay nada en la prueba del ciclo while o el ciclo mismo que pueda cambiarlo). Si ingresó a la función cuando no había ningún carácter esperando en el hardware UART, podría terminar en un bucle infinito que nunca se detuvo, incluso cuando se recibió un carácter.
  • el compilador podría mover la lectura del registro de recepción antes del ciclo while; de ​​nuevo, porque no hay nada en la función que indique que *recv_regel ciclo ha cambiado, no hay razón para que no se pueda leer antes de entrar en el ciclo.

Los volatilecalificadores garantizan que el compilador no realice estas optimizaciones.

Michael Burr
fuente
5
+1 para explicación. Y tengo una pregunta: ¿qué pasa con los métodos volátiles constantes? Si tengo una clase, a la que se accede por muchos hilos (aunque el acceso está sincronizado con mutex), mis métodos const también tienen que ser volátiles (ya que alguna variable podría ser cambiada por otro hilo)
Sasa
39
  • volatile le dirá al compilador que no optimice el código relacionado con la variable, generalmente cuando sabemos que se puede cambiar desde "afuera", por ejemplo, por otro hilo.
  • const le dirá al compilador que está prohibido que el programa modifique el valor de la variable.
  • const volatilees algo muy especial que probablemente verá utilizado exactamente 0 veces en su vida (tm). Como era de esperar, significa que el programa no puede modificar el valor de la variable, pero el valor se puede modificar desde el exterior, por lo que no se realizarán optimizaciones en la variable.
mingos
fuente
12
Pensé que las volatilevariables suelen ser lo que sucede cuando comienzas a jugar con el hardware, no con otros hilos. Donde he visto que se const volatileusan es en cosas como registros de estado mapeados en memoria o similares.
SÓLO MI OPINIÓN correcta
2
Por supuesto, tienes toda la razón, el multihilo es solo un ejemplo, pero no el único :).
mingos
25
Si trabaja con sistemas integrados, verá esto muy a menudo.
Daniel Grillo
28

No es porque la variable sea constante que no haya cambiado entre dos puntos de secuencia.

La constidad es una promesa que hace de no cambiar el valor, no que el valor no cambiará.

Alexandre C.
fuente
9
Más uno por señalar que los constdatos no son "constantes".
Bogdan Alexandru
7

Necesitaba usar esto en una aplicación incrustada donde algunas variables de configuración se encuentran en un área de la memoria flash que puede actualizarse con un cargador de arranque. Estas variables de configuración son 'constantes' durante el tiempo de ejecución, pero sin el calificador volátil, el compilador optimizaría algo como esto ...

cantx.id = 0x10<<24 | CANID<<12 | 0;

... calculando previamente el valor constante y usando una instrucción de ensamblaje inmediata, o cargando la constante desde una ubicación cercana, de modo que se ignoren las actualizaciones del valor CANID original en el área flash de configuración. CANID tiene que ser constante volátil.

push2eject
fuente
7

En C, const y volatile son calificadores de tipo y estos dos son independientes.

Básicamente, const significa que el programa no puede modificar el valor.

Y volátil significa que el valor está sujeto a cambios repentinos (posiblemente desde fuera del programa).

De hecho, el estándar C menciona un ejemplo de declaración válida que es constante y volátil. El ejemplo es

"Extern const volatile int real_time_clock;"

donde real_time_clock puede ser modificable por hardware, pero no puede ser asignado, incrementado o decrementado.

Así que ya deberíamos tratar const y volatile por separado. Además, este calificador de tipo también se aplica a struct, union, enum y typedef.

usuario2903536
fuente
5

Puede usar const y volatile juntos. Por ejemplo, si se supone que 0x30 es el valor de un puerto que se cambia solo por condiciones externas, la siguiente declaración evitaría cualquier posibilidad de efectos secundarios accidentales:

const volatile char *port = (const volatile char *)0x30;
Paso
fuente
4

constsignifica que la variable no puede ser modificada por el código c, no que no pueda cambiar. Significa que ninguna instrucción puede escribir en la variable, pero su valor aún puede cambiar.

volatilesignifica que la variable puede cambiar en cualquier momento y, por lo tanto, no se pueden usar valores en caché; cada acceso a la variable debe ejecutarse en su dirección de memoria.

Dado que la pregunta está etiquetada como "incrustada" y suponiendo que tempes una variable declarada por el usuario, no un registro relacionado con el hardware (ya que estos generalmente se manejan en un archivo .h separado), considere:

Un procesador integrado que tiene memoria de datos de lectura y escritura (RAM) volátil y memoria de datos de solo lectura no volátil, por ejemplo, memoria FLASH en la arquitectura von-Neumann, donde los datos y el espacio del programa comparten un bus común de datos y direcciones.

Si declara const temptener un valor (al menos si es diferente de 0), el compilador asignará la variable a una dirección en el espacio FLASH, porque incluso si se le asignó una dirección RAM, todavía necesita memoria FLASH para almacenar el valor inicial de la variable, lo que hace que la dirección RAM sea una pérdida de espacio ya que todas las operaciones son de solo lectura.

En consecuencia:

int temp;es una variable almacenada en la RAM, inicializada a 0 al inicio (cstart), se pueden usar valores en caché.

const int temp;es una variable almacenada en (lectura) FLASH, inicializada a 0 en el momento del compilador, se pueden usar valores en caché.

volatile int temp; es una variable almacenada en la RAM, inicializada a 0 al inicio (cstart), los valores en caché NO se utilizarán.

const volatile int temp; es una variable almacenada en (de lectura) FLASH, inicializada a 0 en el momento del compilador, los valores almacenados en caché NO se utilizarán

Aquí viene la parte útil:

Hoy en día, la mayoría de los procesadores integrados tienen la capacidad de realizar cambios en su memoria no volátil de solo lectura mediante un módulo de función especial, en cuyo caso const int tempse puede cambiar en tiempo de ejecución, aunque no directamente. Dicho de otra forma, una función puede modificar el valor en la dirección donde tempse almacena.

Un ejemplo práctico sería utilizarlo temppara el número de serie del dispositivo. La primera vez que se ejecuta el procesador integrado, tempserá igual a 0 (o el valor declarado) y una función puede usar este hecho para ejecutar una prueba durante la producción y, si tiene éxito, solicitar que se le asigne un número de serie y modificar el valor de temppor medio de una función especial. Algunos procesadores tienen un rango de direcciones especial con memoria OTP (programable una vez) solo para eso.

Pero aquí viene la diferencia:

Si const int tempes un ID modificable en lugar de un número de serie programable por única vez y NO se declara volatile, se puede usar un valor en caché hasta el próximo inicio, lo que significa que el nuevo ID podría no ser válido hasta el próximo reinicio, o peor aún, algunas funciones podría usar el nuevo valor mientras que otros podrían usar un valor almacenado en caché más antiguo hasta reiniciar. Si se const int tempdeclara voltaile, el cambio de ID entrará en vigor de inmediato.

Michael Kusch
fuente
Wow, esta respuesta es larga
2

En términos simples, el valor en la variable 'const volatile' no se puede modificar mediante programación, pero se puede modificar mediante hardware. Volátil aquí es para evitar cualquier optimización del compilador.

rajeshsam
fuente
1

Usamos la palabra clave 'const' para una variable cuando no queremos que el programa la cambie. Mientras que cuando declaramos una variable 'const volatile', le estamos diciendo al programa que no la cambie y al compilador que esta variable se puede cambiar inesperadamente a partir de una entrada proveniente del mundo exterior.

Ali
fuente