#include <iostream>
struct Foo
{
int a;
bool i;
bool b;
};
struct A
{
int a;
bool i;
};
struct B : public A
{
bool b;
};
int main()
{
std::cout << sizeof(Foo) << sizeof(B) << std::endl;
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Because a compiler is free to pad structures as it sees fit.
This is implementation dependent.
My guess is as follows.
Foo has no padding between i and b.
B has padding between i and b, because A is padded out to
$SOME_ALIGNMENT_VALUE.
Again, this is a guess, the Standard imposes no requirements one way or
the other.
On Feb 28, 5:38 pm, "Mathias Gaunard" <loufo...@gmail.com> wrote:
> Why, in the following code, is sizeof(Foo) different from sizeof(B) ?
> (only tested with GCC on x86)
> Is there a restriction in the language preventing this from being the
> case ?
>
> #include <iostream>
>
> struct Foo
> {
> int a;
> bool i;
> bool b;
>
> };
>
> struct A
> {
> int a;
> bool i;
>
> };
>
> struct B : public A
> {
> bool b;
>
> };
>
> int main()
> {
> std::cout << sizeof(Foo) << sizeof(B) << std::endl;
>
> }
>
This depends on the compiler and the OS on which you run it.
Lets take an example of an OS where 4 bytes is a word.
Struct Foo will fit in two words or 8 bytes.
Where as B which has two components strictly:
1. A part of B: Requires two words with some padding ( 1 word for the
int and 1 word for bool (with padding))
2. B part of B : Requires one word with some padding ( 1 word for bool
(with padding))
So B requires 3 words or 12 bytes in total.
> Why, in the following code, is sizeof(Foo) different from sizeof(B) ?
> (only tested with GCC on x86)
Why should it not be? They are not the same types. You cannot assign
a Foo to a B, or a B to a Foo. Why do you expect that they would have
the same size?
> Is there a restriction in the language preventing this from being the
> case ?
No, there is no restriction. But there is neither a requirement nor a
guarantee that they will be the same. Or that they will have
different sizes.
> #include <iostream>
>
> struct Foo
> {
> int a;
> bool i;
> bool b;
> };
>
> struct A
> {
> int a;
> bool i;
> };
>
> struct B : public A
> {
> bool b;
> };
>
> int main()
> {
> std::cout << sizeof(Foo) << sizeof(B) << std::endl;
> }
Consider this paragraph from section 3.9 of the C++ standard:
"Object types have alignment requirements (3.9.1, 3.9.2). The
alignment of a complete object type is an implementation defined
integer value representing a number of bytes; an object is allocated
at an address that meets the alignment requirements of its object
type."
Also consider writing a program that outputs sizeof(B) and sizeof
(bool) and see what you get.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
> Why, in the following code, is sizeof(Foo) different from sizeof(B) ?
> (only tested with GCC on x86)
> Is there a restriction in the language preventing this from being the
> case ?
>
> #include <iostream>
>
> struct Foo
> {
> int a;
> bool i;
> bool b;
> };
>
> struct A
> {
> int a;
> bool i;
> };
>
> struct B : public A
> {
> bool b;
> };
[snip]
The packing is an implementation-defined thing. sizoef(A) also
happens to be sizeof(Foo). So B is necessarily going to include the
additional bool and align up to the next 4 byte quantity. If you need
specific alignment, use the #pragma pack to ensure A is smaller:
#pragma pack(push,2)
struct A
{
int a;
bool i;
};
struct B : public A
{
bool b;
};
#pragma pack(pop)
That #pragma is pretty common.
Usually one cares about these things for binary compatibility such as
with protocols or encoding. If you're getting into situations where
you'd like to be 64-bit clean, also, be sure to use types that don't vary
based on platform, e.g., int32_t, found in the common (but not in
Windows) non-C++ C99 <stdint.h>. Otherwise, you'll be in for some
surprises when you migrate.
The real question is why you expect them to be the same.
> (only tested with GCC on x86) Is there a restriction in the
> language preventing this from being the case ?
The language makes only very limited guarantees with regards to
the layout of PODs, and even less for non-PODs. There are
almost no restrictions; it's up to the compiler.
> #include <iostream>
> struct Foo
> {
> int a;
> bool i;
> bool b;
>
> };
Just a guess: on a 32 bit machine (x86), sizeof(Foo) is 8.
There's no guarantee of this, of course, and on an x86, it could
also be 6 and the code would work. (That's not the case on
other processors, of course; if Foo had a size of 6 on a Sparc,
accessing Foo::a on the second element in an array would cause a
core dump.)
> struct A
> {
> int a;
> bool i;
> };
sizeof(A) is probably also 8. Alignment oblige.
> struct B : public A
> {
> bool b;
> };
Off hand, I'd expect 12: an A (of 8 bytes) followed by a bool,
and enough padding to ensure alignment. But other arrangements
are possible. (The empty base class optimization doesn't apply,
since A is not empty. And I'm not sure that the compiler is
allowed to reduce the size of the A sub-object otherwise.)
About the only case I'd expect B and Foo to have the same size
is if the compiler ignored alignment restrictions. While this
is allowed by the x86 architecture, it has significant run-time
cost, and of course, many other architectures don't allow it at
all---ignore alignment on a Sparc, and you get a core dump.
(There is one other case where B and Foo might have the same
size: on a machine where bool was the same size as int. Either
an embedded processor, where sizeof(int)==1, or a word addressed
machine, where the implementor decided to put bool on a word,
rather that a byte, on the grounds that byte access was
significantly slower.)
--
James Kanze (GABI Software) email:james...@gmail.com
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
template <std::size_t Len, class ... Types> struct aligned_union
whose nested typedefs describe the alignment of a uniont of the
given types, Types... (using the variadic template notation for
unpacking the parameter pack ...Types, as described here:
http://www.osl.iu.edu/~dgregor/cpp/variadic-templates.pdf
) How would a similar template be defined for calculating
the offsets of a struct containing the same types? The motivation
doing this is so that a space efficient tuple can be defined which
is as space efficient as boost fusion's tuple:
http://boost.cvs.sourceforge.net/boost/boost/boost/fusion/tuple.hpp
The method used in fusion to achieve this efficiency is to generate
the member declarations with tools described in:
http://www.boost.org/libs/preprocessor/doc/index.html
IOW, the preprocessor tools generate:
T0 m0;
T1 m1;
...
TN mN;
where N=sizeof(Types...) (where sizeof... is defined in the
aforementioned .pdf file and returns the number of types
in Types...). IOW, aligned_struct<Len,T0,T1,...,TN>::offsets
would be an instance of:
template<std::size_t... Offsets>struct offsets_struct;
where sizeof(Offsets...) == sizeof(Types...),
Because I would expect my compiler to make the more efficient layout
for Foo, considering both space and alignment requirements.
And the more efficient layout for B would be Foo.
It seems
struct B : public A
{
/* some things */
};
is actually implemented as
struct B
{
A some_name;
/* some things */
};
which is less efficient than "inlining" the members of A, simply
because the non-used space of A induced by its alignment can't be
reused.
struct B
{
/* the members of A */
/* some things */
};
has the same capabilities and is more efficient.
You can still cast a B* to an A* safely.
It is kinda weird, since I've usually seen inheritance-like tricks in
C being implemented like this.
> About the only case I'd expect B and Foo to have the same size
> is if the compiler ignored alignment restrictions.
There is no need to ignore any alignement restriction for that to
happen.
> > > Why, in the following code, is sizeof(Foo) different from sizeof(B) ?
> > The real question is why you expect them to be the same.
> Because I would expect my compiler to make the more efficient
> layout for Foo, considering both space and alignment
> requirements.
It makes the most efficient layout it can, considering both
space and alignment.
> And the more efficient layout for B would be Foo.
> It seems
> struct B : public A
> {
> /* some things */
> };
> is actually implemented as
> struct B
> {
> A some_name;
> /* some things */
> };
Of course it is. Nothing else works.
> which is less efficient than "inlining" the members of A, simply
> because the non-used space of A induced by its alignment can't be
> reused.
If you don't require the code to work, then you can optimize a
lot of things.
The standard already has a few exceptions where code is not
required to work: the empty base class optimization, and the
eliding of copy constructors. You're arguing for it to add
more.
Your A was a POD. Consider what happens when you memcpy into
it. Even if it wasn't, consider what happens when you copy it,
while initializing the elements of B differently.
A compiler can optimize for speed or for space. Optimized for
space, on an Intel, the size of Foo and the size of B would be
the same. And the size of A would be 5. Optimize for speed,
and you need to respect alignment. Most compilers today
optimize for speed, at least by default.
> struct B
> {
> /* the members of A */
> /* some things */
> };
> has the same capabilities and is more efficient.
> You can still cast a B* to an A* safely.
But you can't use the A* safely. For example:
static A someA ;
B someB ;
*static_cast< A* >( &someB ) = someA ;
--
James Kanze (GABI Software) email:james...@gmail.com
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
--
Not if you memcpy onto the A* (and you can do that because A is
POD).
In fact, even if you make A non-POD by adding a constructor, the
compiler internally might choose to implement the assignment operator
for A with an instruction that does "copy 64 bits", which would still
clobber the members of B if they were packed into the "unused" space
of A.
I think that if A is non-POD then B /may/ be layed out as Foo. Of
course, it doesn't have to be, and doing so might break the code of
people who assume that their base code is "almost POD". (*You* may
not care about such code, but compiler writers have to balance the
competing demands of making portable code more efficient and not
breaking non-portable code.)
>
> It is kinda weird, since I've usually seen inheritance-like tricks in
> C being implemented like this.
>
> > About the only case I'd expect B and Foo to have the same size
> > is if the compiler ignored alignment restrictions.
>
> There is no need to ignore any alignement restriction for that to
> happen.
Agreed.