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?
¿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.
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.
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?
Respuesta rápida: elimine -Werror de su Makefile. Solo con esta opción habilitada, la advertencia se tratará como un error.
kevin vermeer