Tengo una cola de búfer de anillo FIFO simple que estoy usando en mi programa C integrado (usando el compilador TI C28x C/C++ que es bastante similar a GCC para C89 sin las extensiones). Los datos se empujan y extraen con la cola de las interrupciones, por lo que las colas deben ser volátiles.
Implementé el código de cola en sí mismo sin usar volatile para que el usuario de la cola tenga la opción de elegir si una cola es volátil o no (quiero usar esto en varios proyectos con diferentes usos), declarando que el identificador es volátil objeto de cola en el uso, en lugar de definir el objeto de cola en sí mismo como volátil en la implementación.
es decir, en que.c:
struct QUE_Obj { /* Object & members are not defined as volatile. */ void * data; uint16_t capacity; uint16_t head; uint16_t tail; uint16_t size; bool full; bool empty; } /* Implementation uses all non-volatile types. */ QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity) { /* ... */ QUE_Handle q = (QUE_Handle)malloc(sizeof(struct QUE_Obj)); /* ... */ return q; } /* ... */en cola.h:
typedef QUE_Obj * QUE_Handle; QUE_Handle QUE_init(void * data, uint_least8_t size, uint16_t capacity)en principal.c:
/* Data buffer and queue handle declared to be for volatile data. */ static volatile uint16_t buffer[BUFFER_LENGTH] = {0}; volatile QUE_Handle que = QUE_init((void *)buffer); /* Buffer passed without volatile. */ Entonces, mi pregunta es, en esa última línea en C cuando lanzo el búfer para void * ¿elimina esto la utilidad de la volatilidad?
¿Debería definir los miembros de QUE_Obj para que siempre sean volátiles y ajustar los tipos utilizados en la implementación para que sean volátiles independientemente del uso de la cola?
Preguntado de otra manera, las funciones push() y pop() se llaman desde las rutinas del servicio de interrupción, pero su implementación no "sabe" sobre la volatilidad, ¿se optimizarán?
No debe acceder a datos volátiles a través de un puntero no volátil. Considere el siguiente ejemplo sencillo:
volatile int volatileVar; int* nonVolatilePtr = &volatileVar; Cada vez que su código accede a volatileVar a través nonVolatilePtr el compilador no sabe que los datos a los que está accediendo son volátiles y podrían optar por optimizar los accesos (lo que claramente es un comportamiento no deseado). Veo muy pocos usos de punteros no volátiles a datos volátiles.
Si espera que las rutinas de servicio de interrupción (o similares) accedan a su cola, haría que toda la estructura de datos fuera volátil.