Strenge Alias- und Overlay-Vererbung

8

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?

    
PSkocik 20.02.2017, 19:20
quelle

2 Antworten

9

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:

%Vor%

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.

    
M.M 20.02.2017, 20:52
quelle
1
___ tag123c ___ C ist eine universelle Computerprogrammiersprache, die für Betriebssysteme, Bibliotheken, Spiele und andere Hochleistungsanwendungen verwendet wird. Dieses Tag sollte bei allgemeinen Fragen zur C-Sprache verwendet werden, wie in der Norm ISO 9899: 2011 definiert. Fügen Sie ggf. ein versionsspezifisches Tag wie c99 oder c90 für Fragen zu älteren Sprachstandards hinzu. C unterscheidet sich von C ++ und es sollte nicht mit dem C ++ - Tag kombiniert werden, wenn ein rationaler Grund fehlt. ___ tag123struct ___ Ein Schlüsselwort in verschiedenen Programmiersprachen, deren Syntax C ähnelt oder von C abgeleitet ist (C ++, C #, Swift, Go usw.). Verwenden Sie ein spezielles Programmiersprachen-Tag, um Fragen zu markieren, die die Verwendung einer 'struct' als Syntax beinhalten, und Semantik kann sprachabhängig sein. Schlüsselwort definiert oder deklariert einen Datentyp, der aus anderen Datentypen besteht. Jedes Mitglied einer Struktur hat seinen eigenen Speicherbereich (im Gegensatz zu einer "Union", deren Mitglieder einen einzigen Speicherbereich teilen). ___ tag123languagelawyer ___ Für Fragen zu den Feinheiten formeller oder autoritativer Spezifikationen von Programmiersprachen und Umgebungen. ___ tag123strictaliasing ___ Striktes Aliasing ist eine Annahme, die vom C- oder C ++ - Compiler gemacht wird, dass die Rückstellung von Zeigern auf Objekte unterschiedlichen Typs sich niemals auf denselben Speicherort bezieht (d. h. sie aliasieren sich nicht gegenseitig). ___ qstntxt ___

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?

    
___ answer42353998 ___

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.

    
___ answer42544644 ​​___

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.

    
___ qstnhdr ___ Strenge Alias- und Overlay-Vererbung ___
supercat 02.03.2017 00:18
quelle