sizeof an object that have same base class as member objects.

Discussion in 'C++' started by Yen Kwoon, May 23, 2008.

  1. Yen Kwoon

    Yen Kwoon Guest

    Note: This problem is related to gcc but after some back and forth in
    group gnu.gcc.help it seems to have morph into more of a c++
    specificiation question, hence the transplanting to this group.

    The original post at gnu.gcc.help can be found at this link
    http://groups.google.com/group/gnu....0/2148a6c1ac6119e1?lnk=st&q=#2148a6c1ac6119e1

    Here's the question:

    class base {
    public:
    base(){};
    ~base(){};

    };

    class data : public base {
    public:
    data(){};
    ~data(){};
    private:
    int member;

    }__attribute__((__packed__));

    class group : public base {
    public:
    group(){};
    ~group(){};
    private:
    data d1;
    data d2;
    data d3;

    } __attribute__((__packed__));

    int main(int argc, char **argv) {
    std::cout << "base = " << sizeof(base) << std::endl;
    std::cout << "data = " << sizeof(data) << std::endl;
    std::cout << "group = " << sizeof(group) << std::endl;
    return (0);

    }

    The output of the program is:
    base = 1
    data = 4
    group = 13

    The result of sizeof(group) is puzzling as it should be 12 if EBO
    (empty base optimization) worked for both class data and group.
    Apparently EBO kicked in for _ONLY_ one of them. If EBO didn't work at
    all, sizeof(group) should be 16.

    Removing the extension of class base from either class group or data
    will cause sizeof(group) to return 12. It seems that gcc is unable to
    fully apply EBO when a class and its member inherits the same empty
    base class.

    The same code had been tested on microsoft msvc compiler and realview
    arm compiler, both correctly optimizes the code and give the correct
    value as 12.

    Is this a known bug with gcc 3.4.5? (Note: I'm using MinGW) I dug
    through the bugbase but couldn't come up with anything. Maybe EBO
    isn't the problem at all.

    Thanks!
    Yen Kwoon, May 23, 2008
    #1
    1. Advertising

  2. Yen Kwoon

    Ian Collins Guest

    Yen Kwoon wrote:
    >
    > Here's the question:
    >
    > class base {
    > public:
    > base(){};
    > ~base(){};
    >
    > };
    >
    > class data : public base {
    > public:
    > data(){};
    > ~data(){};
    > private:
    > int member;
    >
    > }__attribute__((__packed__));
    >
    > class group : public base {
    > public:
    > group(){};
    > ~group(){};
    > private:
    > data d1;
    > data d2;
    > data d3;
    >
    > } __attribute__((__packed__));
    >
    > int main(int argc, char **argv) {
    > std::cout << "base = " << sizeof(base) << std::endl;
    > std::cout << "data = " << sizeof(data) << std::endl;
    > std::cout << "group = " << sizeof(group) << std::endl;
    > return (0);
    >
    > }
    >
    > The output of the program is:
    > base = 1
    > data = 4
    > group = 13
    >
    > The result of sizeof(group) is puzzling as it should be 12 if EBO
    > (empty base optimization) worked for both class data and group.
    > Apparently EBO kicked in for _ONLY_ one of them. If EBO didn't work at
    > all, sizeof(group) should be 16.
    >

    I would have expected sizeof(group) to be 12 (even without the gcc
    specific __attribute__), looks like a bug.

    It is 12 with Sun CC.

    > Is this a known bug with gcc 3.4.5? (Note: I'm using MinGW) I dug
    > through the bugbase but couldn't come up with anything. Maybe EBO
    > isn't the problem at all.
    >

    4.0.0 also reports 13 and 16 without the __attribute__ directive.

    --
    Ian Collins.
    Ian Collins, May 23, 2008
    #2
    1. Advertising

  3. Yen Kwoon

    Yen Kwoon Guest

    >
    > Then Sun CC seems to be wrong.
    >

    That means Microsoft VS8 compiler and RVCT ARM compiler are wrong as
    well :-(

    > I agree with the opinions expressed in the cited gnu.gcc.help thread: the
    > base class subobject of the group class and the base class subobject of
    > d1 are of the same type and cannot be assigned the same address (I
    > believe the general intent is that no two objects of the same type may
    > have the same address):
    >
    > "In 10.0.5:
    > A base class subobject may be of zero size (clause 9); however,
    > two subobjects that have the same class type and that belong to
    > the same most derived object must not be allocated at the same
    > address (5.10).
    > "
    >
    > Thus I think gcc is correct to assign size 13 to the group class. Note
    > that this will hurt performance because of misaligned access if you are
    > using arrays of group objects (and otherwise you would not have to worry
    > about its size, right?). But by specifying __attribute__ you have told
    > the compiler you know better.
    >

    You are probably correct. The original motivation of transplanting
    this question to this group is to verify that the specification in
    question is relevant. Did gcc interpret that paragraph correctly
    whereas the other 3 compilers failed to?
    Hopefully readers on this group can try out the same code on more
    compilers and report the results.
    Yen Kwoon, May 23, 2008
    #3
  4. Yen Kwoon

    James Kanze Guest

    On May 23, 7:56 am, "Alf P. Steinbach" <> wrote:
    > * Yen Kwoon:
    > > Note: This problem is related to gcc but after some back and forth in
    > > group gnu.gcc.help it seems to have morph into more of a c++
    > > specificiation question, hence the transplanting to this group.


    > > The original post at gnu.gcc.help can be found at this link
    > >http://groups.google.com/group/gnu.gcc.help/browse_thread/thread/ece5...


    > > Here's the question:


    > > class base {
    > > public:
    > > base(){};
    > > ~base(){};
    > > };

    >
    > > class data : public base {
    > > public:
    > > data(){};
    > > ~data(){};
    > > private:
    > > int member;
    > > }__attribute__((__packed__));


    > > class group : public base {
    > > public:
    > > group(){};
    > > ~group(){};
    > > private:
    > > data d1;
    > > data d2;
    > > data d3;
    > > } __attribute__((__packed__));


    > > int main(int argc, char **argv) {
    > > std::cout << "base = " << sizeof(base) << std::endl;
    > > std::cout << "data = " << sizeof(data) << std::endl;
    > > std::cout << "group = " << sizeof(group) << std::endl;
    > > return (0);
    > > }


    > > The output of the program is:
    > > base = 1
    > > data = 4
    > > group = 13


    > > The result of sizeof(group) is puzzling as it should be 12
    > > if EBO (empty base optimization) worked for both class data
    > > and group. Apparently EBO kicked in for _ONLY_ one of them.
    > > If EBO didn't work at all, sizeof(group) should be 16.


    > > Removing the extension of class base from either class group
    > > or data will cause sizeof(group) to return 12. It seems that
    > > gcc is unable to fully apply EBO when a class and its member
    > > inherits the same empty base class.


    > > The same code had been tested on microsoft msvc compiler and
    > > realview arm compiler, both correctly optimizes the code and
    > > give the correct value as 12.


    > > Is this a known bug with gcc 3.4.5? (Note: I'm using MinGW)


    > Only if the compiler's specification (in this case presumably
    > of non-standard extension "attribute(packed)") says it should
    > apply EBO.


    > The standard does not require any optimization.


    > For example, a compiler where sizeof(bool) == 4000000 is conforming.


    The question is misstated, first because the example code isn't
    standard C++ (so we can't really say what the standard says
    about it), and second because the problem has nothing to do with
    size anyway (and as you point out, the standard doesn't really
    make any guarantees with regards to size). Add the following
    function to base:

    base* base::addr() { return this ; }

    make all of the members public, then try:

    int
    main()
    {
    group g ;
    assert( g.addr() != g.d1.addr() ) ;
    }

    That assertion is guaranteed to pass: the standard does not
    allow g.addr() (which returns the address of base in group) to
    be equalt to g.d1.addr() (which returns the address of base in
    data). It doesn't fail with g++, so g++ is fine. It does fail
    with both Sun CC and VC++, so those compilers have an error.

    (I don't believe that it's possible to correctly implement this
    on a 32 bit machine and still have sizeof(group) == 12. But the
    standard doesn't say one way or the other; the fact that VC++ or
    Sun CC say sizeof(group) == 12 is NOT an error per se on their
    part. The fact that the above assertion fails is, however.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 23, 2008
    #4
  5. Yen Kwoon

    James Kanze Guest

    On 23 mai, 11:06, "Alf P. Steinbach" <> wrote:
    > * James Kanze:


    [...]
    > > The question is misstated, first because the example code isn't
    > > standard C++ (so we can't really say what the standard says
    > > about it), and second because the problem has nothing to do with
    > > size anyway (and as you point out, the standard doesn't really
    > > make any guarantees with regards to size). Add the following
    > > function to base:


    > > base* base::addr() { return this ; }


    > > make all of the members public, then try:


    > > int
    > > main()
    > > {
    > > group g ;
    > > assert( g.addr() != g.d1.addr() ) ;
    > > }


    > > That assertion is guaranteed to pass: the standard does not
    > > allow g.addr() (which returns the address of base in group) to
    > > be equalt to g.d1.addr() (which returns the address of base in
    > > data). It doesn't fail with g++, so g++ is fine. It does fail
    > > with both Sun CC and VC++, so those compilers have an error.


    > > (I don't believe that it's possible to correctly implement this
    > > on a 32 bit machine and still have sizeof(group) == 12.


    > Oh, no problemo. :) For the in-practice the compiler can let
    > the address of an empty base class sub-object be (or seem to
    > be) anything, as long as it's unique for that complete object,
    > and as long as assignments are translated to no-ops.


    In theory, yes, but it's going to be tricky if == and != are
    going to work correctly, along with the implicit casts down and
    the explicit casts up.

    > But for a moment, after reading Paavo's replies and before
    > reading yours (I instinctively think when reading your
    > articles, although not always successfully), I thought the
    > same as you write here, and would probably have written
    > something along those lines, to correct myself, if you hadn't
    > caused me to think...


    > The problem here is that the formal seems to refer to the in-practice:


    > "allocated at the same address" seems to say something about
    > reality, not about the abstract machine's &-operator.


    Now that you mention it, it does sound like the wording could
    stand some improvement.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 23, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Siemel Naran
    Replies:
    4
    Views:
    785
    Micah Cowan
    Jan 12, 2005
  2. Alex Vinokur
    Replies:
    7
    Views:
    486
    Clark S. Cox III
    Aug 14, 2006
  3. Replies:
    32
    Views:
    912
    Jerry Coffin
    Aug 18, 2006
  4. cppquester

    sizeof(derived) >= sizeof(base)?

    cppquester, Oct 7, 2011, in forum: C++
    Replies:
    1
    Views:
    300
    Juha Nieminen
    Oct 7, 2011
  5. Nikolai Weibull

    sizeof(Class)/sizeof(Object)

    Nikolai Weibull, Dec 31, 2004, in forum: Ruby
    Replies:
    2
    Views:
    144
    Robert Klemme
    Dec 31, 2004
Loading...

Share This Page