Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

sizeof() issue on gcc version 3.4.5

7 views
Skip to first unread message

ykhun

unread,
May 21, 2008, 10:57:13 PM5/21/08
to
Posted this on the gcc bug mailing list but didn't get any reply.
Hopefully someone here encountered this issue before and know what's
wrong.

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!

Paul Pluzhnikov

unread,
May 22, 2008, 11:46:12 AM5/22/08
to
ykhun <YenK...@gmail.com> writes:

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

Same result with gcc-4.3.0 (latest) on i686.

> The result of sizeof(group) is puzzling as it should be 12 if EBO
> (empty base optimization) worked for both class data and group.

I believe this may be prohibited by the standard.

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).

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.

ykhun

unread,
May 22, 2008, 8:32:24 PM5/22/08
to
> I believe this may be prohibited by the standard.
>
> 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).

Hi Paul,
Thanks for pointing that spec out but the code sample doesn't seem to
infringe on 10.0.5, which exists for very good reasons.
10.0.5 would apply if the subobjects are zero size. All three of them
aren't. Each of them holds a single 4-byte int which gives them non-
zero size and no chance of being allocated at the same address.

Paul Pluzhnikov

unread,
May 23, 2008, 12:23:24 AM5/23/08
to
ykhun <YenK...@gmail.com> writes:

> Thanks for pointing that spec out but the code sample doesn't seem to
> infringe on 10.0.5, which exists for very good reasons.
> 10.0.5 would apply if the subobjects are zero size. All three of them
> aren't. Each of them holds a single 4-byte int which gives them non-
> zero size and no chance of being allocated at the same address.

There are two zero-sized subobjects of type "base" that I can see.
Here are their addresses (which can't be equal). Given "group *g":

(base*) g;
(base*) &g->d1;

I am not sure this interpretation is correct. You may want to ask
this in comp.lang.c++ to be sure.

Ulrich Eckhardt

unread,
May 23, 2008, 1:40:26 AM5/23/08
to
ykhun wrote:
> class base {
> public:
> base(){};
> ~base(){};
> };

Layout:
- 1 byte dummy

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

Layout:
- 1 byte dummy from baseclass
- 4 byte int, at the same address as dummy (EBO)

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

Layout:
- 1 byte dummy from baseclass
- 3 times 4 byte for d1..d3

> 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.

This is correct. You basically have these objects as part of a 'group':

base (baseclass)
base (part of d1)
int (part of d1)
base (part of d2)
int (part of d2)
base (part of d3)
int (part of d3)

The 'base' (which is empty) and int parts can be merged using EBO when
forming class 'data'. The reason is that the two objects have different
types still. The quoted phrase from the standard says so. However, you
can't merge an additional 'base' object into the same address as a 'data'
object, because it would have the same address as the contained 'base'
subobject.

> 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.

Note: if d1 was actually a different type or you could reorder d1..d3 so
that the first one was a different type, you could actually cause EBO to
kick in.

> 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.

I wouldn't necessarily call this correct:

group g;
base& b1 = g;
data& d = g.d1;
base& b2 = d;
// distinct objects must have distinct addresses
assert(&b1 != &b2);

In any case, I would ask the question in comp.lang.c++.moderated.

Uli

0 new messages