Betrachten Sie dieses Codebeispiel:
%Vor%Ich dachte immer, dass etwas wie das Übergeben von B * an A * und das Verwenden von A * zum Manipulieren des B * -Objekts eine strenge Aliasing-Verletzung ist. Aber dann erkannte ich, dass der Standard das wirklich nur erfordert:
Auf ein Objekt soll sein gespeicherter Wert nur durch einen L-Wert zugreifen Ausdruck, der einen der folgenden Typen aufweist: 1) ein Typ, der kompatibel ist mit dem effektiven Typ des Objekts, (...)
und Ausdrücke wie ap->x
haben den richtigen Typ und die richtige Adresse, und der Typ von ap
sollte dort nicht wirklich wichtig sein (oder?). Dies würde meines Erachtens bedeuten, dass diese Art der Overlay-Vererbung korrekt ist, solange die Substruktur nicht als Ganzes manipuliert wird.
Ist diese Interpretation fehlerhaft oder scheinbar im Widerspruch zu dem, was die Autoren des Standards beabsichtigt haben?
Die Zeile mit *ap =
ist eine strenge Aliasing-Verletzung: Ein Objekt vom Typ B
wird mit einem lvalue-Ausdruck vom Typ A
geschrieben.
Angenommen, die Zeile war nicht vorhanden und wir sind auf ap->x = 10; ap->y = 20;
gezogen. In diesem Fall wird ein Lvalue vom Typ int
verwendet, um Objekte vom Typ int
zu schreiben.
Es besteht Uneinigkeit darüber, ob dies eine strenge Aliasing-Verletzung ist oder nicht. Ich denke, dass der Buchstabe des Standards sagt, dass es nicht ist, aber andere (einschließlich GCC- und Clang-Entwickler) betrachten ap->x
als implizierend, dass *ap
aufgerufen wurde. Die meisten stimmen zu, dass die Definition des Standards für striktes Aliasing zu ungenau ist und verbessert werden muss.
Beispielcode, der Ihre Strukturdefinitionen verwendet:
%Vor% Für mich gibt dies 214
at -O2
und 2
at -O3
mit gcc aus.
Die generierte Assembly auf godbolt für gcc 6.3 war:
zeigt, dass der Compiler die Funktion zu:
umgeordnet hat %Vor% und deshalb muss der Compiler berücksichtigen, dass ap->x
nicht bp->x
aliasieren darf.
Betrachten Sie dieses Codebeispiel:
%Vor%Ich dachte immer, dass etwas wie das Übergeben von B * an A * und das Verwenden von A * zum Manipulieren des B * -Objekts eine strenge Aliasing-Verletzung ist. Aber dann erkannte ich, dass der Standard das wirklich nur erfordert:
Auf ein Objekt soll sein gespeicherter Wert nur durch einen L-Wert zugreifen Ausdruck, der einen der folgenden Typen aufweist: 1) ein Typ, der kompatibel ist mit dem effektiven Typ des Objekts, (...)
und Ausdrücke wie union
haben den richtigen Typ und die richtige Adresse, und der Typ von union
sollte dort nicht wirklich wichtig sein (oder?). Dies würde meines Erachtens bedeuten, dass diese Art der Overlay-Vererbung korrekt ist, solange die Substruktur nicht als Ganzes manipuliert wird.
Ist diese Interpretation fehlerhaft oder scheinbar im Widerspruch zu dem, was die Autoren des Standards beabsichtigt haben?
Die Zeile mit union
ist eine strenge Aliasing-Verletzung: Ein Objekt vom Typ %code% wird mit einem lvalue-Ausdruck vom Typ %code% geschrieben.
Angenommen, die Zeile war nicht vorhanden und wir sind auf %code% gezogen. In diesem Fall wird ein Lvalue vom Typ %code% verwendet, um Objekte vom Typ %code% zu schreiben.
Es besteht Uneinigkeit darüber, ob dies eine strenge Aliasing-Verletzung ist oder nicht. Ich denke, dass der Buchstabe des Standards sagt, dass es nicht ist, aber andere (einschließlich GCC- und Clang-Entwickler) betrachten %code% als implizierend, dass %code% aufgerufen wurde. Die meisten stimmen zu, dass die Definition des Standards für striktes Aliasing zu ungenau ist und verbessert werden muss.
Beispielcode, der Ihre Strukturdefinitionen verwendet:
%Vor%Für mich gibt dies %code% at %code% und %code% at %code% mit gcc aus. Die generierte Assembly auf godbolt für gcc 6.3 war:
%Vor%zeigt, dass der Compiler die Funktion zu:
umgeordnet hat %Vor%und deshalb muss der Compiler berücksichtigen, dass %code% nicht %code% aliasieren darf.
Wenn C89 geschrieben wurde, wäre es für einen Compiler unpraktisch gewesen, die Common Initial Sequence -Garantie für Unionen zu halten, ohne auch für Struct Pointers zu halten. Im Gegensatz dazu würde die Angabe der CIS-Garantien für Strukturzeiger nicht bedeuten, dass die Gewerkschaften ein ähnliches Verhalten zeigen würden, wenn ihre Adresse nicht vergeben würde. Da die GUS-Garantien seit Januar 1974 - noch bevor das Schlüsselwort %code% der Sprache hinzugefügt wurde - auf Struct-Zeigern anwendbar waren und eine Menge Code jahrelang auf ein solches Verhalten unter Umständen angewiesen war, die Objekte nicht plausibel einbeziehen konnten von %code% type, und dass die Autoren des C89 mehr daran interessiert waren, den Standard prägnanter zu machen, als ihn "sprachanwaltsfest" zu machen, würde ich vorschlagen, dass C89 die CIS-Regel in Bezug auf Gewerkschaften und nicht auf Strukturzeiger umschreibt war mit ziemlicher Sicherheit durch den Wunsch motiviert, Redundanz zu vermeiden, und nicht darum, Compilern die Freiheit zu lassen, aus dem Weg zu gehen, um 15 Jahre Präzedenzfall bei der Anwendung von CIS-Garantien auf Strukturzeiger zu verletzen.
Die Autoren von C99 erkannten, dass in einigen Fällen die Anwendung der CIS-Regel auf Strukturzeiger die ansonsten nützliche Optimierung beeinträchtigen könnte, und spezifizierte, dass, wenn ein Zeiger eines Strukturtyps zur Inspektion eines CIS eines Mitglieds eines anderen verwendet wird Die CIS-Garantie gilt nur, wenn eine Definition eines vollständigen Unionstyps vorliegt, der beide Strukturen enthält. Damit Ihr Beispiel mit C99 kompatibel ist, müsste es also eine Definition eines %code% -Typs enthalten, der beide Ihrer Strukturen enthält. Diese Regel scheint durch den Wunsch motiviert worden zu sein, es Compilern zu erlauben, die Anwendung des CIS auf Fälle zu beschränken, in denen sie Grund zu der Annahme haben könnten, dass zwei Typen in ähnlicher Weise verwendet werden könnten, und Code zuzulassen, dass Typen in Beziehung stehen um ein neues Sprachkonstrukt für diesen Zweck hinzuzufügen.
Die Autoren von gcc scheinen zu denken, dass, weil es ungewöhnlich wäre, dass ein Code einen Zeiger auf ein Mitglied einer Union erhält und dann auf ein anderes Mitglied einer Union zugreifen möchte, die bloße Sichtbarkeit einer vollständigen Unionstyp-Definition nicht ausreichen, um einen Compiler zur Einhaltung von CIS-Garantien zu zwingen, auch wenn sich die meisten Anwendungen des CIS immer auf Strukturzeiger und nicht auf Gewerkschaften bezogen haben. Folglich verweigern die Autoren von gcc die Unterstützung von Konstrukten wie deins auch in Fällen, in denen der C99-Standard dies erfordern würde.
Tags und Links c language-lawyer struct strict-aliasing