Char und Float im Struct 8 Byte groß?



  • Hallo,

    kann mir mal einer erklären, warum ein float und ein char im Struct 8 Byte groß sind?

    struct Struct {
        float f;
        char c;
    };
    

    sizeof(Struct) -> 8, es sollte doch aber eigentlich 5 sein. Hat das mit den CPU-Registern zu tun, die auf meinem 64 bit System entsprechend 4 Byte groß sind?



  • http://de.wikipedia.org/wiki/Speicherausrichtung

    Edit: Ok, Draveres link ist besser^^


  • Administrator

    Nennt man Padding: http://en.wikipedia.org/wiki/Data_padding

    Grüssli



  • Okay, und warum hat ein Struct eine Größe von 2 Byte, wenn er seine leere Basis nochmal als Member definiert? Eigentlich müsste er doch nur eine Größe von einem Byte haben, denn wenn der Struct statt der Basis ein anderes leeres Member definiert, hat er auch nur eine Größe von eins.

    struct Base { };
    
    struct Derived : public Base { // -> 2 Byte
        Base a;
    };
    
    struct Another { };
    
    struct AnotherDerived : public Base { // -> 1 Byte
        Another a;
    };
    

  • Mod

    Eine Klasse kann nie die Größe 0 haben, aber eine leere Basisklasse kann zu einer Größe von 0 optimiert werden, wenn dadurch die Gesamtgröße der erbenden Klasse nicht 0 wird. Das nennt man dann empty base optimization.



  • Bei beiden varianten erbst du von leeren Basisklassen. Warum ist die eine dann größer als die andere?



  • Das ist mir klar, nur warum hat der untere Struct dann eine Größe von eins? Warum kommt es darauf an, ob man den Basisstruct als Member definiert oder ein beliebigen anderen Struct, ob das ganze zwei oder ein Byte groß ist? Warum braucht Base im oberen Beispiel ein Byte mehr, obwohl beide leer sind?



  • @Q: GCC 4.6:
    sizeof(Derived) -> 2 Byte
    sizeof(AnotherDerived) -> 1 Byte



  • Sinnfrei?? schrieb:

    @Q: GCC 4.6:
    sizeof(Derived) -> 2 Byte
    sizeof(AnotherDerived) -> 1 Byte

    Ich weiß. Genau das find ich ja so komisch. Beides mal erbst du von leeren basisklassen und hast einen leeren member.
    SeepJ's erklärung erklärt das irgendwie nicht vollständig^^



  • Btw, MSVC++ 10 sagt, dass beides 1 Byte groß ist. Also ein Compiler Bug?


  • Mod

    Sinnfrei?? schrieb:

    Btw, MSVC++ 10 sagt, dass beides 1 Byte groß ist. Also ein Compiler Bug?

    Es ist eine kann Optimierung, keine muss Optimierung.



  • Find' ich aber trotzdem komisch. Ich denke nicht, dass die GCC-Entwickler das mit Absicht so gemacht haben. Man sollte sie vielleicht mal drauf hinweisen...

    EBCO (empty base class optimization) ist toll. Schaut man bei libstdc++ nach, wie sie unique_ptr implementiert haben, dann sieht das in etwa so aus:

    template<class T, class Deleter = default_deleter<T> >
    class unique_ptr {
      tuple<T*,Deleter> data_;
    public:
      ...
    };
    

    und da der default_deleter zustandslos (leer) ist, tuple<> über Vererbung implementiert ist, und der GCC EBCO durchführt, wird sizeof(unique_ptr<T*>)==sizeof(T*) gelten. 🙂



  • Tuple ist über vererbung implementiert?

    Soll das heißen, dass
    Tuple<int, int> zweimal von int erbt?



  • tuple<A, B, C, D, E> erbt von tuple<B, C, D, E> erbt von tuple<C, D, E> erbt von tuple<D, E> erbt von tuple<D>.


  • Mod

    314159265358979 schrieb:

    tuple<A, B, C, D, E> erbt von tuple<B, C, D, E> erbt von tuple<C, D, E> erbt von tuple<D, E> erbt von tuple<D>.

    Das ist eine Möglichkeit, so macht es z.B. g++; Mehrfachvererbung wäre auch möglich:
    tuple<A,B,C> erbt dann von __tuple_element<0,A>, __tuple_element<1,B>, __tuple_element<2,C> usw.
    Möglicherweise kann das eine besser als das andere optimiert werden, das wäre dann allerdings ein reines QoI-Artefakt.



  • Also lohnt es sich, einen "Bug"report zu schreiben?


  • Mod

    C++03 schrieb:

    1.8 The C+ + object model [intro.object]
    ...
    5 Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class sub-objects may have zero size. An object of POD4) type (3.9) shall occupy contiguous bytes of storage.

    C++11 schrieb:

    1.8 The C++ object model [intro.object]
    ...
    6 Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.4

    1. Under the “as-if” rule an implementation is allowed to store two objects at the same machine address or not store an object at all if the program cannot observe the difference (1.9).

    Das Verhalten von msvc ist möglicherweise beim alten Standard noch zulässig, einen Bug-Report halte ich hier nicht für besonders sinnvoll. Im Zweifelsfall ist das bei Microsoft sowieso eher ein Feature.
    Hier ist ein verwandter Report, mit Änderungsdatum März 2011. Trotzdem ist dieser Teil offenbar danach noch einmal geändert worden. Die gegenwärtigen Regeln sind also noch ziemlich neu.


Anmelden zum Antworten