Ich bin verwirrt über die C++ - Aliasing-Regel und ihre möglichen Auswirkungen. Betrachten Sie den folgenden Code ein:C/C++ striktes Aliasing, Object Lifetime und moderne Compiler
Wenn ein:
int main() { int32_t a = 5; float* f = (float*)(&a); *f = 1.0f; int32_t b = a; // Probably not well-defined? float g = *f; // What about this? }
auf die Spezifikationen ++ C Sehen, Abschnitt 3.10.10, technisch keine der gegebenen Code scheint die "Aliasing-Regeln" dort gegeben zu verletzen Programm versucht, den gespeicherten Wert eines Objekts durch einen L-Wert von anderen als einer der folgenden Typen zuzugreifen das Verhalten undefiniert:
... eine Liste qualifizierter Accessor-Typen ...
*f = 1.0f;
bricht nicht die Regeln, weil es keinen Zugriff auf einen gespeicherten Wert gibt, d.h. ich schreibe gerade in den Speicher über einen Zeiger. Ich lese nicht aus dem Gedächtnis oder versuche hier einen Wert zu interpretieren.- Die Zeile
int32_t b = a;
verstößt nicht gegen die Regeln, weil ich auf den ursprünglichen Typ zugreife. - Die Linie
float g = *f;
bricht nicht die Regeln aus dem gleichen Grund.
In another thread, Mitglied CortAmmon macht tatsächlich den gleichen Punkt in einer Reaktion, und fügte hinzu, dass eine mögliche undefinierte Verhalten lebendig Objekte durch schreibt entstehen, wie in *f = 1.0f;
, für die von der Norm berücksichtigt würden Definition des Begriffs " Objektlebensdauer "(was für POD-Typen trivial zu sein scheint).
JEDOCH: Es gibt viel von Beweisen im Internet, dass über Code wird UB auf modernen Compilern produzieren. Siehe zum Beispiel here und here.
Die Argumentation in den meisten Fällen ist, dass der Compiler frei ist, &a
und f
als nicht aliasing gegenseitig zu betrachten und daher frei, Befehle neu zu planen.
Die große Frage ist jetzt, ob solch ein Compilerverhalten tatsächlich eine "Überinterpretation" des Standards wäre.
Das einzige Mal, dass der Standard speziell über "Aliasing" spricht, ist in einer Fußnote zu 3.10.10, wo klargestellt wird, dass dies die Regeln sind, die Aliasing regeln sollen.
Wie ich bereits erwähnt habe, sehe ich keinen der oben genannten Code gegen den Standard, aber es würde von einer großen Anzahl von Menschen (und möglicherweise Compiler Menschen) für illegal gehalten werden.
Ich würde wirklich einige Abklärung hier wirklich schätzen.
Kleines Update:
Als Mitglied BenVoigt Recht darauf hingewiesen, int32_t
mit float
auf einigen Plattformen nicht ausrichten kann, so dass der gegebene Code in Verletzung der „Lagerung von ausreichender Ausrichtung und Größe“ Regel sein kann. Ich würde gerne sagen, dass int32_t
bewusst auf float
auf den meisten Plattformen ausgerichtet wurde und dass die Annahme für diese Frage ist, dass die Typen tatsächlich ausrichten.
Kleines Update # 2:
Da mehrere Mitglieder darauf hingewiesen haben, int32_t b = a;
die Linie ist wahrscheinlich eine Verletzung der Norm, wenn auch nicht mit absoluter Sicherheit. Ich stimme diesem Standpunkt zu und, ohne jeden Aspekt der Frage zu ändern, bitte Leser, diese Zeile von meiner obigen Aussage auszuschließen, dass keiner der Codes gegen den Standard verstößt.
Schreiben ist eine Form des Zugriffs so viel wie das Lesen ist. –
Wenn das wahr wäre, würde der Standard eher "Zugriff auf die Erinnerung eines Objekts durch ..." sagen. Aber was es sagt ist "Zugriff auf den gespeicherten Wert", was nicht der Code ist. – rsp1984
Neben anderen Problemen mit diesem Code hatten Sie nie ein Objekt vom Typ 'float', weil Sie nie" Speicher von ausreichender Größe und korrekter Ausrichtung erhalten haben ". 'a' ist so groß und ausgerichtet für' int', nicht 'float', und einige Plattformen werden Sie wirklich wissen lassen (um es freundlich zu sagen). –