significado reservadas palabras lenguaje claves campos c arm volatile bit-fields

lenguaje - palabras reservadas en cy su significado



campos de bits volátiles y no volátiles (2)

Es mi lectura del estándar C11 que no es apropiado usar un campo de bits para esto, incluso si ambos se declararon como volatile . El siguiente extracto es de 3.14 Ubicación de la memoria :

  1. Ubicación de la memoria
    O bien un objeto de tipo escalar, o una secuencia máxima de campos de bits adyacentes, todos con un ancho distinto de cero
  2. NOTA 1 Dos hilos de ejecución pueden actualizar y acceder a ubicaciones de memoria separadas sin interferir entre sí.

  3. NOTA 2 No es seguro actualizar simultáneamente dos campos de bits no atómicos en la misma estructura si todos los miembros declarados entre ellos también son campos de bits (de longitud no nula) , independientemente de los tamaños de esos campos de bits intermedios. resultando ser.

No hay excepción dada por volatile . Por lo tanto, no sería seguro utilizar el campo de bits anterior si ambos hilos de ejecución (es decir, el principal y el ISR) si ISR ​​actualizará un indicador y el principal actualizará otro. La solución dada es agregar un miembro de tamaño 0 entre ellos para forzarlos a colocarse en diferentes ubicaciones de memoria. Pero, una vez más, significaría que ambas banderas consumirían al menos un byte de memoria, por lo que nuevamente es simplemente más sencillo usar un unsigned char o bool unsigned char campo unsigned char bit para ellos:

struct { volatile bool flag1; bool flag2; unsigned foo; // something else accessed in main loop } flags;

Ahora se colocarán en diferentes ubicaciones de memoria y se pueden actualizar sin que interfieran entre sí.

Sin embargo, la volatile de flag1 sigue siendo estrictamente necesaria porque, de lo contrario, las actualizaciones de flag1 serían libres de efectos secundarios en el hilo principal, y el compilador podría deducir que puede mantener ese campo solo en un registro, o que nada debe actualizarse en absoluto. .

Sin embargo, se debe tener en cuenta que bajo C11 , incluso las garantías de volatile pueden no ser suficientes: 5.1.2.3p5 :

Cuando el procesamiento de la máquina abstracta se interrumpe por la recepción de una señal, no se especifican los valores de los objetos que no son objetos atómicos sin bloqueo ni de tipo volátil sig_atomic_t, como lo es el estado del entorno de coma flotante. El valor de cualquier objeto modificado por el controlador que no sea un objeto atómico sin bloqueo ni de tipo volátil sig_atomic_t se vuelve indeterminado cuando el controlador finaliza, al igual que el estado del entorno de coma flotante si el controlador lo modifica y no lo restaura. a su estado original.

Por lo tanto, si se requiere compatibilidad total, flag1 debería ser, por ejemplo, de tipo volatile _Atomic bool ; incluso podría ser posible usar un campo de _Atomic . Sin embargo, ambos requieren un compilador C11.

Por otra parte, puede consultar los manuales de su compilador si garantizan que el acceso a dichos objetos volátiles también se garantiza que es atómico.

Estoy escribiendo un código para CPU Cortex-M0 y gcc. Tengo la siguiente estructura:

struct { volatile unsigned flag1: 1; unsigned flag2: 1; unsigned foo; // something else accessed in main loop } flags;

flag1 es leído y escrito desde el controlador de interrupción de GPIO y el bucle principal. flag2 solo se lee y escribe en el bucle principal.

El ISR se ve así:

void handleIRQ(void) { if (!flags.flag1) { flags.flag1 = 1; // enable some hw timer } }

El ciclo principal se ve así:

for (;;) { // disable IRQ if (flags.flag1) { // handle IRQ flags.flag1 = 0; // access (rw) flag2 many times } // wait for interrupt, enable IRQ }

Al acceder a flag2 en el bucle principal, ¿el compilador optimizará el acceso a él para que no se vaya a buscar o almacenar en la memoria cada vez que se lea o se escriba en el código?

No me queda claro porque para establecer flag1 en ISR, tendrá que cargar un char completo, establecer un bit y almacenarlo de nuevo.


La bandera volátil para un solo bit no es tan significativa, es posiblemente incluso dañina. Lo que el compilador podría hacer en la práctica es asignar dos trozos de memoria, posiblemente cada uno de 32 bits de ancho. Debido a que la bandera volátil le impide combinar los dos bits dentro de la misma área asignada, ya que no hay ninguna instrucción de acceso a nivel de bit disponible.

Al acceder a flag2 en el bucle principal, ¿el compilador optimizará el acceso a él para que no se vaya a buscar o almacenar en la memoria cada vez que se lea o se escriba en el código?

Eso es difícil de decir, depende de cuántos registros de datos hay disponibles. Desmonta el código y mira.

En general, no se recomiendan los campos de bits, ya que están tan poco definidos por el estándar. Y en este caso, el bit volátil individual puede llevar a la asignación de memoria extra.

En cambio, debes hacer esto:

volatile bool flag1; bool flag2;

Suponiendo que esos indicadores no son parte de un registro de hardware, en cuyo caso el código era incorrecto desde el principio y ambos deberían ser volátiles.