c arrays type-conversion volatile

c - Reparto de matriz volátil a matriz no volátil



arrays type-conversion (4)

Tengo una matriz de caracteres volatile unsigned char buffer[10] en la que los datos se escriben en una interrupción. Tengo una función que toma un char sin signo * y almacena ese valor en hardware (EEPROM) void storeArray(unsigned char *array) , en este ejemplo, los tres primeros valores. ¿Es seguro convertir la matriz volátil en una matriz no volátil como esta?

storeArray((unsigned char *) buffer);

Leí lo siguiente, que no entiendo muy bien, pero que me preocupa:

6.7.3: 5 Si se intenta referirse a un objeto definido con un tipo calificado volátil mediante el uso de un lvalue con un tipo calificado no volátil, el comportamiento es indefinido.

¿Esto afecta mi código?

Luego tengo esta pregunta de seguimiento: la matriz del búfer solo tiene una sección de datos que quiero almacenar (no puedo cambiar eso), para este ejemplo que comienza con el tercer valor. ¿Es legítimo hacer lo siguiente?

storeArray((unsigned char *) buffer + 3);

Si es así, ¿cómo se ve afectada la conversión, si se agrega 3 a la matriz? BR y gracias!

EDITAR: @Cacahuete Frito vinculó una pregunta muy similar: ¿es `memcpy ((void *) dest, src, n)` con un array `volatile` seguro?


  1. Si la matriz tiene cambios en la interrupción, debe proporcionar un mecanismo para acceder y modificarla de forma atómica. Si no lo hace, cualquier operación de RW o RMW puede fracasar y la información puede ser inconsistente.

  2. El acceso a datos volátiles hace que los parámetros f = unction también sean volátiles. storeArray(volatile unsigned char *) y no se necesitará ningún lanzamiento. El elenco solo elimina la advertencia. Incluso si le pasas datos no volátiles, funcionará también.


Como descubrió, confía en el "comportamiento indefinido". Sin embargo, dependiendo de otras cosas de la separación de las unidades de compilación (y cosas como "optimización de todo el programa" (WPO)) probablemente funcionará. En la mayoría de los casos, el compilador (al menos gcc) no es "lo suficientemente inteligente" para optimizar los accesos de matriz a través de funciones en diferentes unidades de compilación. Dicho esto, la forma limpia, segura y portátil sería copiar la matriz, haciendo que la dependencia de los valores de la matriz no volátil de los volátiles sea visible para el compilador.


Ha encontrado la sección correcta del estándar, este código conduce a un comportamiento indefinido.

Una función que escribe algo "en el hardware" probablemente debería tener un parámetro calificador- volatile , dependiendo de qué es "hardware". Si se trata de un registro mapeado en memoria, un búfer DMA o una memoria no volátil, entonces el parámetro definitivamente debería haber sido un volatile unsigned char* (u opcionalmente, volatile uint8_t* que también debe considerarse como un tipo de carácter).

Detalles: C nos permite iterar a través de cualquier parte de los datos utilizando un puntero de carácter, C17 6.3.2.3/7:

Cuando un puntero a un objeto se convierte en un puntero a un tipo de carácter, el resultado apunta al byte con la dirección más baja del objeto. Los incrementos sucesivos del resultado, hasta el tamaño del objeto, producen punteros a los bytes restantes del objeto.

La parte que cita sobre el acceso a un "lvalue" se refiere al acceso a datos a través de un tipo de puntero diferente al que está almacenado en esa ubicación. Claramente: no importa cuánto emita varios punteros que apunten a él, los datos reales conservan su tipo original.

El acceso a los datos a través del tipo de puntero incorrecto normalmente ni siquiera está permitido, pero nuevamente el acceso de caracteres es una excepción especial a la "regla de alias estricta", C17 6.5 / 7:

Un objeto tendrá acceso a su valor almacenado solo mediante una expresión de valor l que tenga uno de los siguientes tipos:
...
- Un tipo de personaje.

Por lo tanto, puede acceder a cualquier tipo de datos a través de un puntero de carácter, pero si ese puntero no tiene calificación volátil, invoca un comportamiento indefinido según la parte que citó, C17 6.7.3 / 5.

En la práctica, el uso de un tipo de puntero no volátil podría hacer que el compilador optimice el acceso de formas inesperadas. Por lo tanto, esto no es solo un "lenguaje legal" teórico, sino que en la práctica podría obtener un código muy extraño generado con optimizaciones habilitadas. Muchos de los errores muy difíciles de encontrar en los sistemas integrados se originan a partir de una volatile falta.

Con respecto a su pregunta de seguimiento, el lanzamiento y el buffer + 3 no cambian nada: todavía está tratando con un puntero de carácter sin calificador volatile , del mismo tipo. Los datos reales siguen siendo de tipo volatile unsigned char , por lo que no puede acceder a ellos desde la función a través de un unsigned char* .


Sí, la cita estándar que has publicado cubre precisamente lo que estás tratando de hacer. Al hacer el reparto, simulas que los objetos de la matriz son caracteres unsigned char cuando en realidad son caracteres volatile unsigned char , por lo que dentro de la función, te refieres a un objeto volatile través de un lvalue sin un calificador volatile . Comportamiento indefinido.

Si no puede cambiar la función storeArray , tendrá que copiar los datos de la matriz volátil a una no volátil antes de pasarla a la función.

Con respecto a la segunda pregunta: la aritmética del puntero está bien, simplemente convertirá el buffer en un unsigned char* y luego agregará 3 al puntero resultante, apuntando al buffer[3] (pero con la calificación incorrecta).