2010-07-21 8 views
8

Tener este código:las variables volátiles como argumento para funcionar

typedef volatile int COUNT;  

COUNT functionOne(COUNT *number); 

int functionTwo(int *number); 

no puedo deshacerme de algunas advertencias ..

consigo esta advertencia en 1 functionOne prototipo

[ Advertencia] type calificadores ignorados en función return type

y me da esta advertencia 2, donde quiera que llamo functionTwo con un puntero RECUENTO argumento en lugar de un puntero int

[advertencia] fundido descarta calificadores del tipo de destino puntero

, obviamente, las variables/los punteros no se pueden "convertir" a volátiles/no volátiles ... ¿pero cada argumento debe especificarse también como volátil? Entonces, ¿cómo puedo usar cualquier función de biblioteca si ya está definida para una variable no volátil?

EDITAR: Usando gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wextra -Wstrict-prototypes -Wmissing-prototypes …

EDITAR: Después de consejos Jukka Suomela este es un ejemplo de código de advertencia de dos

typedef volatile int COUNT;  

static int functionTwo(int *number) { 
    return *number + 1; 
} 

int main(void) { 
    COUNT count= 10; 
    count = functionTwo(&count); 
    return 0; 
} 
+3

Espero que esta sea una pregunta académica. Si está tratando de resolver un problema real, el enfoque que seleccionó podría llevarlo por un camino difícil. No puedo pensar en una buena razón por la que quieras pasar un elemento volátil a una función por valor. –

+0

@Amardeep No puedo encontrar ninguna razón, pero si no lo hago así, me aparece una segunda advertencia diciéndome que debo especificar volátil en prototipo para las variables volátiles –

Respuesta

2

Es posible que esté fuera de lugar aquí, pero ISN volátil' t algo normalmente asociado con la región de memoria de la pila. Por lo tanto, no estoy seguro si el siguiente prototipo realmente tiene mucho sentido.

volatile int functionOne(volatile int number); 

No estoy seguro de cómo un número entero devuelto puede ser volátil. ¿Qué hará que cambie el valor de EAX? Lo mismo aplica para el entero. Una vez que se coloca el valor en la pila para que pueda pasar como parámetro, ¿qué cambiará su valor?

+0

¡Creo que nada lo hará !, pero si defino el funciona como functionTwo (sin el argumento interior volátil) Obtengo la advertencia Two cada vez que llamo con una variable volátil si eso no está especificado en el prototipo ... –

+0

Según tengo entendido, no se trata de si algo puede cambiar una variable de pila . Declarar una variable de pila como 'volátil' obliga al compilador a leer/escribir siempre el valor desde/hacia la ubicación de la pila en lugar de optimizar el código almacenando en caché los contenidos de esa ubicación de pila en un registro. – Praetorian

0

Es posible que quienes lo escribieron quisieron asegurarse de que todas las operaciones son atómicas y declararon todas las variables int como volátiles (¿es una aplicación MT con mala sincronización?), Por lo que se declaran todas las entradas del código como volátil "por consistencia".

O tal vez al declarar el tipo de función como volátil, esperan detener las optimizaciones de las llamadas repetidas para funciones puras? Un incremento de una variable estática dentro de la función lo resolvería. Sin embargo, trate de adivinar su intención original, porque esto simplemente no tiene ningún sentido.

+1

volátil no tiene nada que ver con la atomicidad. –

+1

http://www.netrino.com/node/80 – ruslik

+0

@Alexandre es posible que esté equivocado, si lo hace var = var + 1 y var no es volátil, entonces se puede cambiar a la mitad de la operación dentro de una interrupción rutina de servicio (para incrustado) o un subproceso, y luego si el compilador no lee valor real var actualizado, la operación que podría ser var = var (Actualizado) + 1, perderá atomicidad haciendo var = var (No actualizada) + 1 , y el valor actualizado se perderá –

2

Si Compilo

typedef volatile int COUNT;  

static int functionTwo(int number) { 
    return number + 1; 
} 

int main(void) { 
    COUNT count = 10; 
    count = functionTwo(count); 
    return 0; 
} 

usando

gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \ 
-Wextra -Wstrict-prototypes -Wmissing-prototypes foo.c 

no consigo ninguna advertencia. Intenté gcc 4.0, 4.2, 4.3 y 4.4. Tu advertencia suena como si estuvieras pasando punteros, no valores, y esa es otra historia ...

EDIT:

Su último ejemplo se debe escribir como esto; de nuevo, no hay advertencias:

typedef volatile int COUNT; 

static int functionTwo(COUNT *number) { return *number + 1; } 

int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; } 

EDIT:

Si no puede cambiar functionTwo:

typedef volatile int COUNT; 

static int functionTwo(int *number) { return *number + 1; } 

int main(void) { 
    COUNT count= 10; 
    int countcopy = count; 
    count = functionTwo(&countcopy); 
    return 0; 
} 

Tenga en cuenta que cualquier acceso a una variable volátil es "especial". En la primera versión con functionTwo(COUNT *number), la función Dos sabe cómo acceder correctamente. En la segunda versión con countcopy, la función principal sabe cómo acceder correctamente al asignar countcopy = copy.

+0

Argumento de la función Dos es "int * number", y no "COUNT * number", cambie eso y luego recibirá las advertencias (Imagine que está tratando con una función de biblioteca que ya es común * int como argumento) pero los vars de tu código son volátiles (+1 para el intento y el ejemplo) –

+0

está bien para un int, pero si tienes un array, no es eficiente desde el punto de vista de la memoria hacer una copia solo para evitar una advertencia –

+0

No se trata de "evitar advertencias" ", se trata de la corrección. :) Con una copia explícita, tendrá la semántica correcta (lo que sea que signifique en su implementación), y sabrá exactamente dónde ha leído o escrito accesos a objetos volátiles. Si solo toma un puntero, descarta el calificador "volátil" y lo pasa a una función de biblioteca, todas las apuestas están desactivadas (comportamiento indefinido). –

2

No entiendo por qué querría tener el calificador volatile en un tipo de devolución de función. La variable a la que le asigna el valor de retorno de la función debe escribirse como volatile.

trate de hacer estos cambios:

typedef int COUNT_TYPE; 
typedef volatile COUNT_TYPE COUNT;  

COUNT_TYPE functionOne(COUNT number); 

COUNT_TYPE functionTwo(COUNT_TYPE number); 

Y al llamar functionTwo(), convierta explícitamente el argumento:

functionTwo((COUNT_TYPE)arg); 

HTH, Ashish.

+4

Exactamente, los valores no pueden ser volátiles. Volatile solo se puede aplicar a algún tipo de almacenamiento (es decir, variables que se colocarán en registros). – Gianni

+0

+1 @Gianni, los valores r no pueden ser 'const' ni' volátiles'. ¿Qué significa eso * incluso * si pudieran serlo? –

+0

@Carl ¿Números imaginarios? http://en.wikipedia.org/wiki/Imaginary_number – Gianni

8

La palabra clave volatile se diseñó para aplicarse a objetos que representan almacenamiento y no a funciones. Devolver un volatile int desde una función no tiene mucho sentido. El valor de retorno de una función no se optimizará (con la posible excepción de las funciones en línea, pero ese es otro caso completo ...), y ningún actor externo lo modificará. Cuando una función regresa, pasa una copia del valor de retorno a la función de llamada. Una copia de un objeto volatile no es ella misma volatile. Por lo tanto, intentar devolver un volatile int dará como resultado una copia, fundiéndolo en un no volátil int, que es lo que está activando los mensajes del compilador. Devolver un volatile int* puede ser útil, pero no un volatile int.

Pasar un objeto por valor a una función hace una copia del objeto, por lo tanto, usar un volatile int como parámetro de función implica necesariamente una conversión que ignora un calificador. Pasar una dirección volátil por es perfectamente razonable, pero no por valor.

De acuerdo con la especificación C, el comportamiento de volatile depende completamente de la implementación, por lo tanto, YMMV.

¿Está utilizando volatile de esta manera para tratar de vencer a algún tipo de optimización del compilador? Si es así, probablemente haya una mejor manera de hacerlo.

Editar: Teniendo en cuenta los cambios a su pregunta, parece que usted puede ser capaz de acercarse a esto de una manera diferente. Si intentas vencer las optimizaciones del compilador, ¿por qué no tomar el enfoque directo y simplemente decirle al compilador que no optimice algunas cosas? Puede usar #pragma GCC optimize o __attribute__((optimize)) para proporcionar parámetros de optimización específicos para una función. Por ejemplo, __attribute__((optimize(0))) debe deshabilitar todas las optimizaciones para una función dada.De esta forma, puede mantener sus tipos de datos no volátiles y evitar los problemas de tipo que tiene. Si deshabilitar todas las optimizaciones es demasiado, también puede activar o desactivar las opciones de optimización individuales con ese atributo/pragma.

Editar: yo era capaz de compilar el código siguiente sin ningún tipo de advertencias o errores:

static int functionTwo(int *number) { 
    return *number + 1; 
} 

typedef union { 
       int i; 
    volatile int v; 
} fancy_int; 

int main(void) { 
    fancy_int count; 
    count.v = 10; 
    count.v = functionTwo(&count.i); 
    return 0; 
} 

Este piratear "técnica" probablemente tiene algún tipo de efectos secundarios extraños, por lo que probarlo completamente antes de uso de producción. Lo más probable es que no sea diferente a la conversión directa de la dirección a (int*), pero no activa ninguna advertencia.

+0

+1 es una opción, intentaré resolverlo con optimización, siguiendo la respuesta de Jukka Suomela, es necesario hacer una copia del objeto, pero creo que debería ser suficiente con un molde, para asegurarse de que los fabricantes de gcc tengan una razón para dar la advertencia de todos modos –

Cuestiones relacionadas