2011-03-04 4 views
19

¿Cuál es el uso de la palabra clave volátil en C/C++? ¿Cuál es la diferencia entre declarar una variable volatile y no declararla como volatile?¿Cuál es el uso de la palabra clave volátil?

+1

Además, [haciendo que el compilador acepte que es volátil] (http: // stackoverflow.com/questions/642568/how-do-i-know-if-gcc-agree-that-something-is-volátil) a veces toma un poco de trabajo. –

+3

ver: http://stackoverflow.com/questions/72552/c-when-has-the-volatile-keyword-ever-helped-you y http://stackoverflow.com/questions/4437527/why-do-we -use-volatile-keyword-in-c – dappawit

+0

posible duplicado de [palabra clave volátil] (http://stackoverflow.com/questions/5620281/volatile-keyword) – EJP

Respuesta

9

Volatile le dice al compilador que la variable puede cambiar sin que lo sepa, por lo que no debería optimizarla.

La única vez que lo he necesitado fue en los días de las tarjetas ISA cuando leía una dirección de memoria para obtener los datos del bus. También hubo un error en el compilador que significaba que volátil no funcionaba.

También puede ser útil en algunos paralelos código /-multihebras

+2

También se usa con bastante frecuencia en sistemas integrados en los que se usan varios registros y dispositivos. mapeado a direcciones de memoria. – user470379

+1

Sí, eso es para lo que lo necesitaba, en ISA de 16 bits, tenía que leer la misma dirección dos veces para obtener los bytes alto/bajo. Desafortunadamente, MS C++ decidió que estos dos bytes siempre eran iguales. –

+0

'volátil' es una frecuencia mal utilizada para primitivas de sincronización cruda. Prácticamente, cada vez que ve la palabra clave 'volátil' fuera del controlador de un dispositivo, debe leerla como 'error'. Casi nunca es la forma correcta de hacerlo ... a menos que seas el autor de una primitiva de sincronización. –

25

El volatile calificador sobre una variable indica al compilador que cada vez que se accede a esta variable, su valor tiene que ser cargado desde la memoria, y que el compilador no puede suponer nada sobre este valor de las tiendas anteriores que ha efectuado.

Por lo tanto, es apropiado siempre que tenga situaciones donde una variable puede tener un valor que no se puede prever en el "hilo de ejecución" actual (en un sentido amplio). Esto incluye:

  • registros de hardware
  • variables de estado en los manejadores de señales
  • las variables en vivo que se utilizan después saltos inesperados, como goto, switch/case, o, más importante, setjmp/longjmp.

volatile es también necesaria (pero no suficiente!) Para el acceso atómica para enhebrar las variables compartidas a las que el acceso no está mutexed. Para ese propósito, volatile no es de ninguna manera suficiente para garantizar el acceso atómico, incluso si solo es para lectura. Para eso, tendrías que usar instrucciones especiales de la CPU que no estén modeladas (o interconectadas) por la máquina abstracta del estándar C actual, C99. El siguiente estándar, C1X, se supone que tiene tales primitivos.

+8

Como no es suficiente, en realidad tampoco es necesario. Simplemente no ayuda. :-) –

+2

@Bo, es necesario junto con las instrucciones especiales que menciono, y también será necesario por las nuevas interfaces que están en proceso. –

-3

cuando usamos la variable simple no volátil en ese momento el compilador intentará optimizar el código, por ejemplo, si está utilizando b = a * a * a; entonces se usará como b = a * 3; pero cuando usa la palabra clave volátil mientras declara la variable "a", la optimización no tendrá lugar por el valor de "a", y todas y cada una de las veces el valor será extraído de la memoria, porque el calificador volátil permitirá otro hardware así como también el proceso para cambiar el valor de la variable.

+0

1) a * a * a! = A * 3, 2) el calificador volatile no permite cambiar la variable; solo advierte al compilador que la variable puede haber obtenido en otro lugar. –

+0

de acuerdo con @ChristianSeverin –

0

Volatile le dice al compilador que el valor de la variable puede cambiar fuera del alcance de su código por ej.

{ 
int x; 
int y; 
} 

El valor de X e Y se limita al ámbito pero en caso de que si estamos modificando su valor desde algún lugar fuera, entonces debe ser marcado como volátiles debido compilador mantener estos valores en el registro temporal y siempre dar el mismo valor en lugar de dar el valor modificado.

Por lo tanto, en tales casos, se debe usar volátil para obtener el valor reciente de esa variable en particular.

3

Volatile le dice al compilador que este valor puede cambiar y que el compilador no debe hacer ninguna optimización en él. Un ejemplo de eso

/** port to read temperature **/ 
#define PORTBASE 0x40000000 

unsigned int volatile * const port = (unsigned int *) PORTBASE; 

for(;;) 
{ 
    if(*port == 300) 
    { 
    /** shutdown the system **/ 
    } 

} 

Si el puerto no es volátil, el compilador asumirá que no se puede cambiar el valor. Nunca hará la comprobación si * port == 300. Sin embargo, el valor se puede cambiar en función del sensor. Ponemos volatilidad para decirle al compilador que no hace ninguna optimización en él. La regla del pulgar es cuando se usan los registros mapeados en la memoria, cuyo valor puede cambiar en función de las circunstancias, y luego se usa la palabra clave volátil.

1

Para la mayoría de los programas C, el objetivo de un objeto es retener lo último que se escribió por código en el contexto de ejecución actual ("hilo", núcleo de CPU, etc.). La forma más fácil para un compilador de realizar un seguimiento del contenido de un objeto es asignar espacio en el almacenamiento y tratar las lecturas y escrituras de esa variable como lecturas y escrituras de ese almacenamiento, pero el almacenamiento en sí mismo no representa el propósito del código: simplemente representa un medio para un fin. Dado unsigned x;, si un compilador ve x+=3; x+6;, la forma más fácil de generar código sería obtener x, agregar 3, almacenar el resultado en x, luego buscar x, agregar 6 y almacenar ese resultado. Sin embargo, la carga y almacenamiento intermedios solo se necesitan cuando el compilador no sabe cómo lograr el mismo efecto de otra manera. A tal código mejor compilador dado a menudo sería capaz de simplificar que simplemente agregar 9.

Especialmente en incrustado o código sistemas, sin embargo, la propósito de un programa puede incluir la carga y el almacenamiento de ciertos valores de ciertos lugares de almacenamiento en una cierta secuencia. Muchas máquinas del mundo real realizan E/S al tener hardware que se activa mediante cargas y almacenamientos de ciertos objetos, y lleva a cabo diversas acciones en respuesta. Por ejemplo, no sería raro tener un objeto que bajo las condiciones correctas causaría que cualquier carácter enviado a él sea pasado a un terminal. El almacenamiento de 'H' y luego 'i' en SERTX, por ejemplo, podría enviar Hi. Hacer que un compilador intente simplificar o consolidar tales secuencias (por ejemplo, decidir omitir la tienda de 'H') dejaría inútiles los programas. Un calificador volatile indica al compilador que, si bien sería libre de consolidar la mayoría de los accesos a la mayoría de los objetos, hay unos pocos para los cuales tales accesos deben realizarse exactamente como están escritos. Efectivamente, uno podría imaginar que para cada tipo escalar (por ejemplo, "sin firmar") hay funciones

int volatile_load_unsigned(unsigned volatile *p); 
void volatile_store_unsigned(unsigned volatile *p, usigned value); 

cuyo comportamiento el compilador no sabe nada sobre, y por lo tanto el código como:

extern volatile unsigned x; 
x+=3; 
x+=6; 

sería interpretado por el compilador como equivalente a:

extern volatile int x; 
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+3); 
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+6); 

de hecho, el código de máquina para realizar un almacén volátil es en la mayoría de los sistemas de el mismo que el código de un Ordin ary store (y no genera ningún tipo de llamada de función ) pero solo la parte del compilador que genera el código de máquina final "sabrá" que - todo lo demás debería tratar el código como si fuera una función cuyos efectos el compilador no sabía nada acerca de.

Desafortunadamente, en nombre de la "optimización", algunos compiladores han dejado tratando los accesos volátiles como llamadas a funciones opacas. Si código llama una función cuyo funcionamiento interno del compilador sabe nada acerca, se debe asumir esa función puede acceder a cualquier y todos los objetos cuya dirección nunca ha sido expuesta al mundo exterior.Aplicando tal tratamiento a volatile -calificado variables permitirá que el código construya un objeto en almacenamiento ordinario, aprovechando la capacidad de consolidar cargas y almacena, almacena la dirección de ese objeto en un puntero volátil , activando algún otro proceso que genera el buffer. Código necesitaría para probar objeto volátil-calificado para asegurar que el contenido del búfer habían sido la salida por completo antes de hacer cualquier otra cosa con que el almacenamiento, sino en las implementaciones que siguen el modelo "función opaca" el compilador se aseguraría de que todas las escrituras para el almacenamiento que se produjo en el código antes de que el almacén volátil que desencadena la operación de salida de hecho generaría instrucciones de almacenamiento que preceden a las instrucciones para el almacén volátil.

Algunos autores de compiladores piensan que es más útil tener compiladores asumen que no es necesario generar las tiendas a las variables no cualificado antes de realizar accesos a los volátiles cualificados. Ciertamente, el Estándar no requiere que las implementaciones reconozcan la posibilidad de que escribir en una variable volátil pueda desencadenar acciones que podrían afectar otras cosas, pero eso no significa que un compilador de calidad para sistemas donde dichos constructos puedan ser útiles no los respalde. Desafortunadamente, el hecho de que los autores de la Norma no quisieran ordenar conductas que serían útiles en algunos sistemas, pero no en otros, ha sido interpretado como una sugerencia de que los escritores de compiladores no deberían soportar tales comportamientos incluso en sistemas en los que son útiles.

Tenga en cuenta que en algunos procesadores, asegurando que una CPU ejecuta instrucciones en una secuencia determinada puede no ser suficiente para asegurar que los efectos de que la instrucción se producen en secuencia. Algunos procesadores incluyen opciones de configuración para garantizar que las operaciones en algunas partes de la memoria se realicen en orden incluso cuando eso reduzca la velocidad de ejecución, y algunos procesadores incluyen otros medios para controlar el orden de ejecución, pero estos problemas están separados de volatile. En una implementación de calidad, volatile se asegurará de que el procesador al menos tenga conocimiento de todas las lecturas y escrituras que deben producirse; un programador puede necesitar realizar pasos adicionales para asegurar que el procesador realmente los realice como se indica, pero decirle al procesador que complete todas las operaciones pendientes antes de que haga cualquier otra cosa no servirá de nada si el compilador no le ha dicho al procesador que algo necesita ser escrito.

0

volátil restringen el compilador no para optimizar el uso de determinada variable que se declara volátil en el código.

Diferencia entre la variable con volátil y sin ella

variable sin volátil

int main()  
{  
    int a = 5; 

    while(a == 5) //compiler replace variable **'a'** with 5 as optimization purpose  
    {   
    } 

    if(a==5)//compiler replace **'a'** with 5 as optimization purpose  
    {  
    } 

    return 0;  
} 

en anteriormente compilador de código asume que el valor de la variable 'a' siempre será 5 , entonces el compilador reemplaza todo 'a' con 5 como propósito de optimización.

variable con volátil

Pero algún valor las variables cambiado por fuera de interrumpir, por lo que aquí siempre se necesitan para conseguir que las variables valor directamente desde Memory.For ello se utilizan volátil.

volatile int a=5; 

while(a==5) //compiler will npt optimize the variable **'a'** and always get the value of **'a'** from Memory 
+0

"* el compilador no optimizará la variable 'a' y siempre obtendrá el valor de 'a' de la Memoria *" La primera parte es verdadera, pero la segunda parte no. Por ejemplo, la CPU aún puede omitir el acceso de la memoria y esto sucede en casi todos los sistemas modernos. –

Cuestiones relacionadas