2010-02-21 13 views
14

supongo que el siguiente me dará 10 enteros volátiles¿Cómo declarar una matriz crea usando malloc a ser volátiles en C++

volatile int foo[10]; 

Sin embargo, no creo que la siguiente va a hacer lo mismo.

volatile int* foo; 
foo = malloc(sizeof(int)*10); 

Por favor, corríjanme si estoy equivocado acerca de esto y cómo puedo tener una serie de elementos volátiles utilizando malloc.

Gracias.

+1

He encontrado una buena explicación aquí: http://www.embedded.com/story/OEG20010615S0107 – Mark

+1

He comenzado una pregunta de usenet sobre esto: http://groups.google.com/group/comp.std .C++/browse_thread/thread/4af91d60c2a1af8a? pli = 1 –

Respuesta

11
int volatile * foo; 

de lectura de derecha a izquierda "foo es un puntero a un int volátil"

así que cualquier Int acceso a través foo, el int habrá volátil.

P.S.

int * volatile foo; // "foo is a volatile pointer to an int" 

==

volatile int * foo; // foo is a pointer to an int, volatile 

foo significado es volátil. El segundo caso es realmente sólo un vestigio de la regla general de derecha a izquierda. La lección que hay que aprender es conseguir en el hábito de usar

char const * foo; 

en lugar de los más comunes

const char * foo; 

Si quieres que las cosas más complicadas como "puntero a una función que devuelve el puntero a int" para hacer cualquier sentido.

P. S., y esto es un colaron (y la principal razón por la que estoy añadiendo una respuesta):

observo que incluyó "multithreading" como una etiqueta. ¿Se da cuenta de que hace poco volátil/nada de bueno con respecto a múltiples hilos?

+3

volátil debe usarse cuando se comparten variables de estado entre subprocesos; particularmente para algoritmos concurrentes libres de bloqueo donde usa esperas ocupadas. P.ej. el hilo 1 girará en esta instrucción: while (barrier); hasta que el hilo 2 establece la barrera = falso. Si no se usaba volátil, el código podría estar bloqueado si el compilador decidiera leer el valor de barrera de su registro local en lugar de la memoria. – Mark

+1

No volátil no inserta una barrera de memoria para todos los compiladores. Consulte http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ –

+0

Sí, está el raro caso en que volátil hace algún bien . Pero un bloqueo de giro requiere una barrera de memoria, o al menos los datos que se leen después de que 'barrier == true' necesita una barrera de memoria. En MSVC volátil implica barreras, pero eso no es estándar. – tony

3

Sí, eso funcionará. No hay nada diferente en la memoria real que es volatile. Es solo una manera de decirle al compilador cómo interactuar con esa memoria.

+0

No estoy seguro. Empecé una pregunta sobre Usenet al respecto: http://groups.google.com/group/comp.std.c++/browse_thread/thread/4af91d60c2a1af8a?pli=1 –

2

Creo que el segundo declara que el puntero es volátil, no lo que apunta. Para conseguir eso, creo que debe ser

int * volatile foo; 

Esta sintaxis es aceptable para gcc, pero estoy teniendo problemas para convincing myself que hace algo diferente.

Encontré una diferencia con gcc -O3 (optimización completa). Por esta (tonto) código de prueba:

volatile int v [10]; 
int * volatile p; 

int main (void) 
{ 
     v [3] = p [2]; 
     p [3] = v [2]; 
     return 0; 
} 

Con volatile, y omitiendo las instrucciones (x86) que no cambian:

movl p, %eax 
    movl 8(%eax), %eax 
    movl %eax, v+12 
    movl p, %edx 
    movl v+8, %eax 
    movl %eax, 12(%edx) 

Sin volátil, se salta la recarga p:

movl p, %eax 
    movl 8(%eax), %edx ; different since p being preserved 
    movl %edx, v+12 
    ; 'p' not reloaded here 
    movl v+8, %edx 
    movl %edx, 12(%eax) ; p reused 

Después de muchos más experimentos de ciencia tratando de encontrar una diferencia, llego a la conclusión de que no hay diferencia. volatile desactiva todas las optimizaciones relacionadas con la variable que reutilizaría un valor establecido posteriormente. Al menos con x86 gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-33). :-)

+1

¿No debería ser al revés? con volátil, debe forzar la recarga de p. – Mark

+0

Esto parece un error de compilación, en realidad. Con volátil, tiene que hacer dos lecturas de 'p', porque el estándar dice que hay dos lecturas (lvalue para validar las conversiones). –

+0

Sí. Lo tuve al revés. Ahora está arreglado. – wallyk

6
volatile int* foo; 

es el camino a seguir. El calificador tipo volátil funciona igual que el calificador de tipo const. Si quieres un puntero a una matriz constante de número entero usted escribiría:

const int* foo; 

mientras que

int* const foo; 

es un puntero constante a un entero que puede en sí mismo ser cambiado. volátil funciona de la misma manera.

1

Muchas gracias a wallyk, yo era capaz de idear un código utilizar su método para generar un poco de montaje para demostrar a mí mismo la diferencia entre los diferentes métodos de puntero.

utilizando el código: y compilar con -03

int main (void) 
{ 
     while(p[2]); 
     return 0; 
} 

cuando p se declara simplemente como puntero, nos quedamos atascados en un bucle que es imposible salir. Tenga en cuenta que si se tratara de un programa de multiproceso y un subproceso diferente escribió p [2] = 0, entonces el programa se rompería fuera del bucle, mientras que y terminar normalmente.

int * p; 
============ 
LCFI1: 
     movq _p(%rip), %rax 
     movl 8(%rax), %eax 
     testl %eax, %eax 
     jne  L6    
     xorl %eax, %eax 
     leave 
     ret 
L6: 
     jmp  L6 

observe que la única instrucción para L6 es ir a L6.

==

cuando p es puntero volátil

int * volatile p; 
============== 
L3: 
     movq _p(%rip), %rax 
     movl 8(%rax), %eax 
     testl %eax, %eax 
     jne  L3 
     xorl %eax, %eax 
     leave 
     ret 

aquí, el puntero de p consigue vuelve a cargar cada iteración de bucle y como consecuencia, el elemento de la matriz también recibe Reloaded. Sin embargo, esto no sería correcta si queríamos una matriz de enteros volátiles ya que esto sería posible:

int* volatile p; 
.. 
.. 
int* j; 
j = &p[2]; 
while(j); 

y resultaría en el bucle que sería imposible para terminar en un programa de multiproceso.

==

finalmente, esta es la solución correcta como Tony explica muy bien.

int volatile * p; 
LCFI1: 
     movq _p(%rip), %rdx 
     addq $8, %rdx 
     .align 4,0x90 
L3: 
     movl (%rdx), %eax 
     testl %eax, %eax 
     jne  L3 
     leave 
     ret 

En este caso la dirección de p [2] se mantiene en valor del registro y no cargado de la memoria, pero el valor de p [2] se vuelve a cargar desde la memoria en cada ciclo del bucle.

también en cuenta que

int volatile * p; 
.. 
.. 
int* j; 
j = &p[2]; 
while(j); 

generará un error de compilación.

Cuestiones relacionadas