FlorianB82 hat geschrieben:Die meisten aktuellen C++-Compiler führen keine Optimierungen aufgrund der Strict-Aliasing-Rules durch - da sollte also trotz der Warnung kein unerwartetes Verhalten aufgrund Optimierung auftreten. Soweit ich aber weiß, führen neuere GCC-Versionen solche Optimierungen durch - hier könntest du dann gegebenenfalls interessante Effekte beobachten.
Da irrst du dich gewaltig! Die Strict-Aliasing-Rule ist Grundnahrungsmittel jedes auch nur annähernd brauchbaren Compilers und für die Performance von C++ von essentieller Bedeutung. Ohne die müsste der Compiler davon ausgehen, dass jede Modifikation eines Objektes potentiell den Wert jedes anderen Objektes verändert, was bedeuten würde, dass der Compiler nach jeder Modifikation irgendeines Objektes die Werte aller anderen Objekte neu aus dem Speicher laden muss, bevor er sie wieder verwenden kann. Oft ist selbst die Strict-Aliasing-Rule nicht genug, genau darum bietet so ziemlich jeder Compiler eine Variante des
restrict Keywords als Extension an...
Nur mal so als kleine Illustration:
Code: Alles auswählen
int blub(int* i, float* f)
{
*i = 10;
*f = 32.0f;
return *i + *f;
}
int main()
{
union
{
float f;
int i;
} x;
return blub(&x.i, &x.f);
}
Jeder gängige Compiler wird dir das – dank Strict-Aliasing-Rule – zu einem
return 42; optimieren. Ändern wir den
int zu
char, sieht die Sache plötzlich völlig anders aus...
FlorianB82 hat geschrieben:Wenn du die Warnung vernünftig losbekommen willst - was ich nur begrüßen kann, da ich ein großer Freund von Warning-Free-Code bin - gibt es immer die Möglichkeit, über einen char-Pointer (signed oder unsigned) zu casten. Gemäß der Strict-Aliasing-Rules dürfen (unsigned/signed) char*-Pointer nämlich jeden beliebigen Typ aliasen, und du bist damit safe und standardkonform.
Die Frage ist nur, was du mit diesem
char* dann tun willst (
signed char wäre übrigens bereits ab hier schon wieder UB, nur
char und
unsigned char dürfen aliasen). Willst du auf irgendein anderes als das erste Byte der Objektrepräsentation, auf die dein
char* zeigt, zugreifen, wirst du Pointerarithmetik betreiben müssen und spätestens dann haben wir UB, denn Pointerarithmetik auf Pointern, die nicht in ein Array oder auf das letzte Element eines Arrays zeigen, ist UB... ;)
FlorianB82 hat geschrieben:Über einen Union zu gehen ist eigentlich auch Murks. Interessant, dass der Compiler da nicht meckert. Wenn mich nicht alles täuscht, erlaubt der C++-Standard nur das Lesen aus einem Feld eines Unions, in das man vorher auch geschrieben hat - alles andere ist UB. Da du das aber genau machen würdest (in i schreiben und aus f lesen), kannste dir das auch sparen. Ist auch nicht besser oder schlechter als der brutalo-cast.
In der Tat; das funktioniert leider alles nicht...