Ist die "leere Basisoptimierung" in GCC konfigurierbar?

8

Betrachten Sie diese Typen:

%Vor%

sizeof(A) > 0 wie vom Standard gefordert.

sizeof(B) sollte wegen der leeren Basisoptimierung 4 sein. Aber auf GCC 4.1.1 ist es 5 (ich benutze ein Paket von 1 in diesem Bereich). Und inkonsistent - einige meiner Dateien bekommen es, manche nicht. Kann nicht sicher sein, was die Unterschiede sind, haben wir ein großes Prjoect.

Bei den anderen drei Compilern, die ich verwende (von Microsoft und Freescale), habe ich dieses Problem nicht. Die Optimierung der leeren Basis ist anscheinend laut diesem Artikel optional.

Gibt es eine Compileroption oder ein Pragma, um dies in GCC 4.1.1 zu tunen? Ich kann das Problem umgehen, aber ich würde gerne verstehen, was zuerst passiert. Ich habe eine Weile gegoogelt und kann scheinbar nichts finden.

    
scobi 13.02.2009, 19:17
quelle

3 Antworten

10

Das passiert immer. Ich poste sofort, bevor ich es herausfinde. Vielleicht bringt mich das Posting dazu, anders zu denken.

Also in meiner Frage war die Probe ein wenig zu vereinfacht. Es ist eigentlich eher so:

%Vor%

sizeof (C1) ist auf allen Plattformen korrekt 4, aber sizeof (C2) ist 9 anstatt 8 auf GCC. Und ... anscheinend ist GCC das Einzige, was es richtig macht, gemäß dem letzten Teil des Artikels, den ich in der ursprünglichen Frage verlinkt habe. Ich zitiere es (von Nathan Meyers) hier:

  

Eine ganze Familie verwandter "leerer Unterobjekte" -Optimierungen ist möglich, vorbehaltlich der ABI-Spezifikationen, die ein Compiler beachten muss. (Jason Merrill hat mir einige davon vor Jahren gezeigt.) Betrachten Sie zum Beispiel drei Strukturelemente der (leeren) Typen A, B und C und eine vierte nicht leere. Sie können übereinstimmend alle die gleiche Adresse haben, solange sie keine Basen untereinander oder mit der enthaltenden Klasse haben. Ein gängiges Problem in der Praxis besteht darin, dass das erste (oder einzige) Mitglied einer Klasse von der gleichen leeren Basis wie die Klasse abgeleitet ist. Der Compiler muss Padding einfügen, so dass sie zwei Unterobjekte unterschiedliche Adressen haben. Dies tritt tatsächlich in Iterator-Adaptern auf, die ein Interator-Mitglied haben, beide abgeleitet von std :: iterator. Ein unvorsichtig implementierter Standard std :: reverse_iterator könnte dieses Problem aufweisen.

Also, die Inkonsistenz, die ich sah, war nur in Fällen, in denen ich das obige Muster hatte. Jeder andere Ort, den ich von einer leeren Struktur herleitete, war in Ordnung.

Einfach genug, um zu arbeiten. Danke allen für die Kommentare und Antworten.

    
scobi 13.02.2009, 19:57
quelle
1

GCC C ++ folgt diesen Regeln mit Standardauffüllung:

HINWEIS: __attribute__((__packed__)) oder das Ändern der Standardverpackung ändert diese Regeln.

  • Klasse EmptyBase {}; - & gt; sizeof (EmptyBase) == 1

  • Eine beliebige Anzahl leerer Basen wird im Strukturoffset auf 0 abgebildet, solange es sich bei allen um eindeutige Typen handelt (einschließlich Eltern).

  • Nicht leere Basiseltern sind einfach in der Reihenfolge, in der sie nur für das Alignment deklariert sind.

  • Wenn das erste Element einer abgeleiteten Klasse, das unmittelbar auf leere Basen folgt, nicht von einer dieser Basen abgeleitet wird, darf es beim ersten ordnungsgemäß ausgerichteten Offset für dieses Element beginnen, das größer als-or ist - gleich der Leer-Basis-Adresse - dies kann die gleiche Adresse wie die Leer-Basis sein.

  • Wenn das erste Element einer abgeleiteten Klasse, das unmittelbar auf leere Basen folgt, von einer dieser Basen abgeleitet wird, beginnt es beim ersten ordnungsgemäß ausgerichteten Offset für dieses Element, das größer als die leere Basisadresse ist - Dies ist nie die gleiche Adresse wie die leeren Basen.

  • Mitglieder, die leere Klassen sind, benötigen mindestens ein Byte Speicher in der enthaltenen Klasse.

MSVC ++ folgt diesen Regeln:

HINWEIS: #pragma pack oder das Ändern der Standardverpackung ändert diese Regeln.

  • Klasse EmptyBase {}; - & gt; sizeof (EmptyBase) == 1

  • Die einzige Möglichkeit, eine leere Basisklasse (oder eine von einer leeren Basis abgeleitete Klasse) mit dem Offset 0 (Null) zu beginnen, ist, wenn es sich um die erste Basisklasse handelt.

  • Eine nicht leere Basisklasse beginnt beim nächsten gültigen Ausrichtungs-Offset für die Basisklasse.

  • Alle leeren Basisklassen scheinen in der abgeleiteten Klasse keinen effektiven Speicher zu haben und haben keinen Einfluss auf den aktuellen Offset, es sei denn, es folgt eine andere leere Basisklasse (oder eine von einer leeren Basis abgeleitete Klasse) Sie sollten die folgende Regel sehen.

  • Eine leere Basisklasse (oder Klasse, die von einer leeren Basis abgeleitet ist), die einer leeren Basisklasse (oder einer von einer leeren Basis abgeleiteten Klasse) folgt, addiert 1 zur aktuellen Offsetposition vor dem Auffüllen der richtige Ausrichtung für die Klasse.

  • Zwischen der letzten Basisklasse und dem ersten Klassenmitglied oder den vft-Pointern gibt es kein Padding (außer zur Ausrichtung). *** HINWEIS: Dies ist eine zu aggressive Leer-Basis-Optimierung, die den C ++ - Standard durchbrechen kann.

  • Mitglieder, die leere Klassen sind, benötigen mindestens ein Byte Speicher in der enthaltenen Klasse.

Adisak 28.05.2009 07:53
quelle
0

Nun, es ist keine vollständige Antwort, aber die GCC-Handbuch erwähnt, dass g ++ manchmal leere Basisklassen mit dem falschen Offset platzieren kann. Siehe das Bit über die Option -Wabi .

    
Michael Kristofik 13.02.2009 19:44
quelle

Tags und Links