Ralf Corsepius
warning: dereferencing type-punned pointer will break strict-aliasing rules
Was will mir diese Warnung sagen?
Genau was sie sagt :) Michael hat ja schon auf die Info-Doku hingewiesen. In Kürze und vereinfacht: Der Standard sagt, dass auf ein Objekt nur mit einem Zeiger des passenden Typs verwiesen kann. Ausnahme sind einzig 'char *' und 'void *', diese können als Alias für beliebige Typen dienen. Also int a; void **v; int *pa = &a; /* OK */ void *pv = (Void *)&a; /* OK */ char *pc = (char *)&a; /* OK */ short *ps = (short *)&a; /* type-punning Warnung */ v = (void **)&pa; /* " " */
Wie bedeutsam ist sie?
Sehr.
Wenn gcc schon warnt, wie sähen die Folgen aus, falls etwas "zerbricht"?
Diese Alias-Regeln macht sich der Compiler zunutze, um den Code (ab -O2) entsprechend zu optimieren. Wird jetzt doch gegen die Regeln verstossen, in dem dieser umgecastete Zeiger dereferenziert wird, können sehr merkwürdige Dinge passieren, eben weil der Compiler nicht damit rechnet. Man hat jetzt mehrere Möglichkeiten: 1) -fno-strict-aliasing verwenden (wie es im Kernel gemacht wird weil die Kernelhacker behaupten, dass sie den Code nicht ändern könnten). Damit wird aber auch die entsprechende Optimierung deaktiviert. 2) Code so umschreiben, dass kein Umcasten nötig ist. Das ist nicht immer oder nur unter viel Aufwand möglich. Ein leicht lösbarer Fall sind z.B. Wrapper um free(), malloc() etc. , die einen 'void **' übergeben bekommen (hatte ich z.B. bei e2fsprogs, xntp und mutt). Hier ändert man die Wrapperfunktionen dahingehend, dass sie nun einen 'void *' erwarten, den man *intern* in 'void **' umcastet. Dann kann man bei den jeweiligen Aufrufen der Funktionen einfach jeglichen Cast entfernen ('void *' akzeptiert jede Art von Zeiger). 3) GCC spezifische Lösungen verwenden. Da wäre zum Einen das neue Attribut may_alias (siehe Info-Doku) zum Anderen die Verwendung von Unions. Beispiel für letzteres: void do_something(double *); long l; union{ long *lp; double *dp; }cv = { &l }; do_something(dp); Laut Standard ist das Verhalten undefiniert, also waren die GCC-Entwickler frei, das Verhalten für den gcc zu definieren. Aber beide Lösungen *sind unportabel*, sprich bei einem anderen Compiler ist nicht sicher, dass es auch funktioniert. Philipp