Ayuda a corregir o ignorar la advertencia de alias en gcc

Tengo un problema al trabajar con la placa de demostración TI/Stellaris EK-LM3S6965 y el software asociado, específicamente el controlador de pantalla OLED. Mi problema no es que no funcione, es que en su mayoría funciona. Excepto por esta sección:

//
// Clear out the buffer used for sending bytes to the display.
//
*(unsigned long *)&g_pucBuffer[0] = 0;  //Line 438
*(unsigned long *)&g_pucBuffer[4] = 0;  //Line 439

lo que hace que gcc se queje:

rit128x96x4.c:438: advertencia: la desreferenciación del puntero con juegos de palabras romperá las reglas estrictas de alias.

El problema ocurre porque g_pucBuffer se declara como una matriz de caracteres:

//*****************************************************************************
//
// Buffer for storing sequences of command and data for the display.
//
//*****************************************************************************
static unsigned char g_pucBuffer[8];

pero estamos accediendo a él como largo (32 bits, 4 caracteres) y, por lo tanto, borrando la matriz en 2 líneas de código en lugar de 8. El uC es un procesador de 32 bits, por lo que debería hacer esto en 2 ciclos después de la configuración . En realidad, utiliza 4 instrucciones, en lugar de la posible instrucción múltiple de 1 tienda en 2 ciclos, pero en este punto estoy más que satisfecho con el rendimiento del compilador (es una arquitectura bastante nueva y el compilador solo tiene unos meses).

Pero, cuando escribo cada byte secuencialmente a 0,

g_pucBuffer[0] = 0;
g_pucBuffer[1] = 0;
g_pucBuffer[2] = 0;
g_pucBuffer[3] = 0;
g_pucBuffer[4] = 0;
g_pucBuffer[5] = 0;
g_pucBuffer[6] = 0;
g_pucBuffer[7] = 0;

cada uno escribe como una sola instrucción. Lo sé, son 4 ciclos, pero quiero hacerlo bien y creo que tengo un código inteligente y seguro. Ahora es más un tema personal. Tengo activada la optimización completa, pero no puedo darme cuenta de que realmente solo quiero que estos 64 bits sean 0 de la manera más simple posible.

Sin embargo, lo que la advertencia quiere que haga es acceder a las variables como caracteres, porque estoy cruzando los límites de bytes (escribiendo g_pucBuffer[0, 1, 2 y 3] en un solo paso). Sé que están alineados con dword, sé que el código funciona en el original, pero quiero que desaparezca la advertencia.

¿Cómo puedo hacer que gcc ignore este problema específico de conversión/aliasing o hacerlo correctamente?

Respuestas (5)

¿Puede en cambio declarar su variable como una unión de una matriz de bytes y una matriz larga?

No sé si esto es más "legal" que su código original sin una lectura cuidadosa de la especificación, pero podría valer la pena investigarlo.

Acabo de aprender la palabra clave union en otra pieza de código. ¡Esta es probablemente la mejor respuesta! (¿Puedo cambiar la selección después de que haya transcurrido este tiempo?) La palabra clave union es poco conocida y poco utilizada, pero este es un ejemplo perfecto.

Una conversión intermedia a (void *), luego una conversión a (long *) puede eliminar la advertencia. Verifiqué esto hoy (al menos con gcc 3.4.5), que

*(long*)(void*)&buffer[0] = 0;

desengaña al compilador de la noción de que el cielo se caerá si lanza &buffer[0] a (long *).

Yo diría que esto es mejor que usar una opción -fno-strict-aliasing, ya que -fno-strict-aliasing tendrá un efecto global, mientras que el reparto intermedio se puede usar caso por caso, y es explícitamente obvio en su fuente real donde ha tratado el problema.

Los efectos globales fueron mi preocupación con la opción del compilador. ¡Gracias por esta mejor solución!

Personalmente, creo que las advertencias del compilador están ahí por una razón. Deshabilitarlos o ignorarlos (como parecen recomendar algunas de las otras respuestas) es una mala idea. -fno-strict-aliasing evita un montón de otras optimizaciones, al final, probablemente perderá mucho más rendimiento que los 4 ciclos que ahorra al hacer el truco del código C.

¿No funcionaría -fno-strict-aliasing?

¡Ay! Este es el tipo de solución gcc-option que estaba buscando. No parece que lo que quería hacer (lanzar mis caracteres demasiado largos) sea en realidad C válido, así que esto es lo que tendré que hacer. Sin embargo, si entiendo correctamente las otras publicaciones sobre esto en la web, esto evita que algunas optimizaciones (en niveles más altos) cambien otras cosas en otras partes de mi código. Pero no estoy haciendo muchas conversiones tontas en otras partes de mi código (solo este búfer), por lo que debería funcionar.
solo tenga en cuenta que la supresión de las advertencias tiene una forma de volver a atormentarlo, ya que una vez que tiene el interruptor de supresión en su compilación, las advertencias posteriores sobre nuevas situaciones tienden a ser sofocadas.
Sí, por supuesto, esto podría evitar algunas optimizaciones.

Respuesta rápida: elimine -Werror de su Makefile. Solo con esta opción habilitada, la advertencia se tratará como un error.