Helfen Sie mit, die Aliasing-Warnung in gcc zu beheben oder zu ignorieren

Ich habe ein Problem bei der Arbeit mit dem TI/Stellaris EK-LM3S6965-Demoboard und der zugehörigen Software, insbesondere dem OLED-Anzeigetreiber. Mein Problem ist nicht, dass es nicht funktioniert, es ist, dass es meistens funktioniert. Bis auf diesen einen Abschnitt:

//
// 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

was dazu führt, dass gcc sich beschwert:

rit128x96x4.c:438: Warnung: Die Dereferenzierung eines typgesponnenen Zeigers verstößt gegen strikte Aliasing-Regeln.

Das Problem tritt auf, weil g_pucBuffer als Zeichenarray deklariert ist:

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

aber wir greifen als Long (32-Bit, 4 Zeichen) darauf zu und löschen so das Array in 2 Codezeilen statt in 8. Der uC ist ein 32-Bit-Prozessor, also sollte er dies in 2 Zyklen nach dem Setup tun . Es verwendet tatsächlich 4 Anweisungen anstelle der möglichen 1 Speicher-Multiple-Anweisung in 2 Zyklen, aber an diesem Punkt bin ich mehr als zufrieden mit der Leistung des Compilers (es ist eine ziemlich neue Architektur und der Compiler ist erst ein paar Monate alt).

Aber wenn ich jedes Byte sequentiell auf 0 schreibe,

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;

es schreibt jeweils als einzelne Anweisung. Ich weiß, es sind 4 Zyklen, aber ich möchte es richtig machen, und ich denke, ich habe einen cleveren und sicheren Code. Es ist jetzt eher ein persönliches Problem. Ich habe die vollständige Optimierung aktiviert, aber es kann nicht herausfinden, dass ich wirklich nur möchte, dass diese 64 Bits so einfach wie möglich 0 sind.

Die Warnung möchte jedoch, dass ich auf die Variablen als Zeichen zugreife, da ich Byte-Grenzen überschreite (Schreiben von g_pucBuffer[0, 1, 2 und 3] in einem einzigen Schritt). Ich weiß, dass sie dword-ausgerichtet sind, ich weiß, dass der Code im Original funktioniert, aber ich möchte, dass die Warnung verschwindet.

Wie kann ich entweder gcc dazu bringen, dieses spezielle Cast/Aliasing-Problem zu ignorieren, oder es richtig machen?

Antworten (5)

Können Sie Ihre Variable stattdessen als Vereinigung eines Byte-Arrays und eines langen Arrays deklarieren?

Ich weiß nicht, ob dies "legaler" ist als Ihr ursprünglicher Code, ohne die Spezifikation sorgfältig zu lesen, aber es könnte sich lohnen, sich damit zu befassen.

Ich habe gerade das Union-Schlüsselwort in einem anderen Codestück gelernt - Dies ist wahrscheinlich die beste Antwort! (Darf ich die Auswahl ändern, nachdem so viel Zeit verstrichen ist?) Das Schlüsselwort union ist wenig bekannt und wird wenig verwendet, aber dies ist ein perfektes Beispiel.

Ein Zwischencast auf (void *) und dann Cast auf (long *) kann die Warnung beseitigen. Ich habe dies heute früher verifiziert (zumindest mit gcc 3.4.5), that

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

desillusioniert den Compiler von der Vorstellung, dass der Himmel einstürzen wird, wenn Sie &buffer[0] auf (long *) werfen.

Ich würde behaupten, dass dies besser ist als die Verwendung einer Option -fno-strict-aliasing, da -fno-strict-aliasing globale Auswirkungen hat, während die Zwischenumwandlung von Fall zu Fall verwendet werden kann und in Ihrem ausdrücklich offensichtlich ist tatsächliche Quelle, wo Sie sich mit dem Problem befasst haben.

Die globalen Auswirkungen waren meine Sorge mit der Compiler-Option. Danke für diese bessere Lösung!

Persönlich denke ich, dass Compiler-Warnungen aus einem bestimmten Grund vorhanden sind. Sie zu deaktivieren oder zu ignorieren (wie einige der anderen Antworten zu befürworten scheinen), ist eine schlechte Idee. -fno-strict-aliasing verhindert eine Reihe anderer Optimierungen, am Ende werden Sie wahrscheinlich viel mehr Leistung verlieren als die 4 Zyklen, die Sie durch den C-Code-Hack sparen.

Würde -fno-strict-aliasing nicht funktionieren?

Ah! Dies ist die gcc-option-Lösung, die ich anstrebte. Es sieht nicht so aus, als ob das, was ich tun wollte (meine Zeichen zu lang setzen), tatsächlich gültiges C ist, also muss ich das tun. Wenn ich die anderen Beiträge dazu im Web richtig verstehe, verhindert dies jedoch, dass einige Optimierungen (auf höheren Ebenen) andere Dinge an anderer Stelle in meinem Code ändern. Aber ich mache nicht viel doofes Casting an anderer Stelle in meinem Code (nur dieser Puffer), also sollte das funktionieren.
Seien Sie sich jedoch bewusst - das Unterdrücken von Warnungen kann Sie zurückrufen, da Sie, sobald Sie den Unterdrückungsschalter in Ihrem Build haben, nachfolgende Warnungen über neue Situationen ersticken.
Ja, das könnte natürlich einige Optimierungen verhindern.

Schnelle Antwort: Entfernen Sie -Werror aus Ihrem Makefile. Nur wenn diese Option aktiviert ist, wird die Warnung als Fehler behandelt.