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

Order of structure members in memory

40 views
Skip to first unread message

Andrew Simmons

unread,
Nov 14, 2002, 8:21:43 AM11/14/02
to
In a posting on another newsgroup, some one said that they had been told
that in C++ it was no longer guaranteed that structure members were laid
out in memory in the same order as they occurred in the structure
declaration. I find this hard to believe, especially given the recent
discussion concerning compatibility between C & C++ - could some
knowledgeable person here either confirm or deny, preferably giving
references to the standard?

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Francis Glassborow

unread,
Nov 14, 2002, 8:05:57 PM11/14/02
to
In message <3DD35AAB...@monitorbm.co.nz>, Andrew Simmons
<andrew....@monitorbm.co.nz> writes

>In a posting on another newsgroup, some one said that they had been
told
>that in C++ it was no longer guaranteed that structure members were
laid
>out in memory in the same order as they occurred in the structure
>declaration. I find this hard to believe, especially given the recent
>discussion concerning compatibility between C & C++ - could some
>knowledgeable person here either confirm or deny, preferably giving
>references to the standard?

struct X {
int y;
float f;
};

struct Y{
int y;
float f;
};

are required to be layout compatible (for compatibility with C)

struct Z {
public: int y;
public: float f;
};

Does not need to be layout compatible. The compiler may re-order data
members that have been declared with different (though possibly
identical) access specifiers.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Ron

unread,
Nov 15, 2002, 1:35:03 AM11/15/02
to
> In a posting on another newsgroup, some one said that they had been
told
> that in C++ it was no longer guaranteed that structure members were
laid
> out in memory in the same order as they occurred in the structure
> declaration. I find this hard to believe, especially given the recent
> discussion concerning compatibility between C & C++ - could some
> knowledgeable person here either confirm or deny, preferably giving
> references to the standard?

And the Standard (s.9.2(12)) says:

Nonstatic data members of a (non-union) class declared without an
intervening access-specifier are allocated so that later members have
higher addresses within a class object. The order of allocation of
nonstatic data members separated by an access-specifier is unspecified
(11.1). Implementation alignment requirements might cause two adjacent
members not to be allocated immediately after each other; so might
requirements for space for managing virtual functions (10.3) and
virtual base classes (10.1).

-- Ron

Sean Kelly

unread,
Nov 17, 2002, 10:16:30 AM11/17/02
to
Francis Glassborow wrote:
>
> struct X {
> int y;
> float f;
> };
>
> struct Y{
> int y;
> float f;
> };
>
> are required to be layout compatible (for compatibility with C)
>
> struct Z {
> public: int y;
> public: float f;
> };
>
> Does not need to be layout compatible. The compiler may re-order data
> members that have been declared with different (though possibly
> identical) access specifiers.

So what about:

struct X {
int y;
float f;

public: int z;
};

Are the order of y and f guranteed and are they guranteed to be at the
start of the struct? Or are all bets off once any explicit access
signifiers are added to the declaration?


Sean

Jerry Coffin

unread,
Nov 17, 2002, 7:41:37 PM11/17/02
to
In article <zBvB9.475$1a1.38...@newssvr21.news.prodigy.com>,
ken...@pacbell.net says...

[ ... ]


> > struct Z {
> > public: int y;
> > public: float f;
> > };
> >
> > Does not need to be layout compatible. The compiler may re-order data
> > members that have been declared with different (though possibly
> > identical) access specifiers.
>
> So what about:
>
> struct X {
> int y;
> float f;
> public: int z;
> };
>
> Are the order of y and f guranteed and are they guranteed to be at the
> start of the struct? Or are all bets off once any explicit access
> signifiers are added to the declaration?

Francis is a very smart guy, so I'm extremely hesitant to disagree
with him, but by my reading, he's wrong this one. According to 9/4:

A POD-struct is an aggregate class that has no non-volatile
data members of type pointer to member, non-POD-struct, non-
POD-union (or array of such types) or reference, and has no
user-defined copy assignment operator and no user-defined
destructor.

According to 8.5.1/1:

An aggregate is an array or a class (clause 9) with no user-
declared constructors (12.1), no private or protected non-
static data members (clause 11), no base classes (clause 10)
and no virtual functions (10.3).

Note that this does _not_ say anything about access specifiers --
only about the actual access itself. You're free to use the public
access specifier as often as you wish, and the class remains POD.

Now, if you had something that was NOT a POD-struct, _then_ you'd
have to look at 9.2/12, which says:

... The order of allocation of non-static data members

separated by an access-specifier is unspecified (11.1).

However, since what you declared IS a POD-struct, the implementation
is required to follow 9.2/17, which says:

A pointer to a POD-struct object, suitably converted using
a reinterpret_cast, points to its initial member...

As such, the compiler _must_ arrange your struct so that y is at the
very beginning of the struct. After that must come f (possibly
separated by some padding) and finally z. Francis's example is
similar -- if you start with a pointer to struct Z, and
reinterpret_cast it to int*, it _must_ point to Z::y; the compiler is
NOT allowed to rearrange the layout to place Z::f before Z::y.

I don't think the rules on POD structs are quite strong enough to
ensure what was really originally intended though. Given a
declaration like:

struct A {
public: int x;
public: int y;
public: int z;
};

The compiler can put the members either in of two possible orders: x-
y-z OR x-z-y. Both of these satisfy the requirement in 9.2/17 but
the latter uses the permission in 9.2/12 to rearrange members other
than the first one even though it's clearly a POD-struct (to which I
don't believe this permission was really intended to apply).

--
Later,
Jerry.

The universe is a figment of its own imagination.

Francis Glassborow

unread,
Nov 17, 2002, 7:42:39 PM11/17/02
to
In message <zBvB9.475$1a1.38...@newssvr21.news.prodigy.com>, Sean
Kelly <ken...@pacbell.net> writes

>So what about:
>
>struct X {
> int y;
> float f;
>public: int z;
>};
>
>Are the order of y and f guranteed and are they guranteed to be at the
>start of the struct? Or are all bets off once any explicit access
>signifiers are added to the declaration?

I have not got time to check the standard but I believe that it requires
that

&y < & f

I have some recollection that it also requires that
for
X x;

static_cast<char *>(&y) == static_cast<char *>(&x)

But I think it places no requirement on z, and I think that it is
allowed to place z so that:

&y < &z < &f

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Nov 18, 2002, 10:25:18 AM11/18/02
to
In message <MPG.184194ada...@news.direcpc.com>, Jerry Coffin
<jco...@taeus.com> writes

>Francis is a very smart guy, so I'm extremely hesitant to disagree
>with him, but by my reading, he's wrong this one. According to 9/4:

Actually what makes me appear so smart is that I try to learn from my
errors. But thanks for the compliment and the thoughtful response.

>
> A POD-struct is an aggregate class that has no non-volatile
> data members of type pointer to member, non-POD-struct, non-
> POD-union (or array of such types) or reference, and has no
> user-defined copy assignment operator and no user-defined
> destructor.

Yes, and I wonder if we should also have said 'has at most one access
specifier that must come before any declarations of non-static data
members. I sort of wonder if there is a defect hiding in here.

>
>According to 8.5.1/1:
>
> An aggregate is an array or a class (clause 9) with no user-
> declared constructors (12.1), no private or protected non-
> static data members (clause 11), no base classes (clause 10)
> and no virtual functions (10.3).
>
>Note that this does _not_ say anything about access specifiers --
>only about the actual access itself. You're free to use the public
>access specifier as often as you wish, and the class remains POD.

Perhaps this is the place where we should have added a restriction to
access specifiers.

>
>Now, if you had something that was NOT a POD-struct, _then_ you'd
>have to look at 9.2/12, which says:
>
> ... The order of allocation of non-static data members
> separated by an access-specifier is unspecified (11.1).

And note that this says nothing about it being a non-POD


>
>However, since what you declared IS a POD-struct, the implementation
>is required to follow 9.2/17, which says:
>
> A pointer to a POD-struct object, suitably converted using
> a reinterpret_cast, points to its initial member...

And for it to be a POD it is intended that it be layout compatible with
all other PODs that have the same declaration sequence. Indeed because
of the C rules about structs that share a common initial sequence
(important for unions) I think we should have said more because the
intent of a POD is that it should be layout compatible with the
equivalent declaration applied by a compatible C compiler.

>
>As such, the compiler _must_ arrange your struct so that y is at the
>very beginning of the struct. After that must come f (possibly
>separated by some padding) and finally z. Francis's example is
>similar -- if you start with a pointer to struct Z, and
>reinterpret_cast it to int*, it _must_ point to Z::y; the compiler is
>NOT allowed to rearrange the layout to place Z::f before Z::y.

I agree, but I think we should be requiring more for a POD and so should

be more restricitve as to what a POD is.

>
>I don't think the rules on POD structs are quite strong enough to
>ensure what was really originally intended though. Given a
>declaration like:

I agree, but I think they should eliminate the following as a POD.

>
>struct A {
>public: int x;
>public: int y;
>public: int z;
>};
>
>The compiler can put the members either in of two possible orders: x-
>y-z OR x-z-y. Both of these satisfy the requirement in 9.2/17 but
>the latter uses the permission in 9.2/12 to rearrange members other
>than the first one even though it's clearly a POD-struct (to which I
>don't believe this permission was really intended to apply).

And I think that a struct (or class) with multiple declarative regions
for data members should not be classified as a POD.

Should we raise an issue (potential DR) on this.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jerry Coffin

unread,
Nov 20, 2002, 11:47:38 AM11/20/02
to
In article <oA47GsAf...@robinton.demon.co.uk>,
francis.g...@ntlworld.com says...

[ ... ]

> But thanks for the compliment and the thoughtful response.

Certainly.

> > A POD-struct is an aggregate class that has no non-volatile
> > data members of type pointer to member, non-POD-struct, non-
> > POD-union (or array of such types) or reference, and has no
> > user-defined copy assignment operator and no user-defined
> > destructor.
> Yes, and I wonder if we should also have said 'has at most one access
> specifier that must come before any declarations of non-static data
> members. I sort of wonder if there is a defect hiding in here.

That depends a bit on viewpoint, I suppose. I doubt there's clear
consensus that the original intent was different from what's in the
standard so it's a really _obvious_ defect, but that doesn't mean
it's immune to improvement either.

> >Now, if you had something that was NOT a POD-struct, _then_ you'd
> >have to look at 9.2/12, which says:
> >
> > ... The order of allocation of non-static data members
> > separated by an access-specifier is unspecified (11.1).
>
> And note that this says nothing about it being a non-POD

True -- my wording was poor. I should have said that this still
applies, but (at least as I'd interpret things) the compiler is only
free to take this permission to the extent that it does NOT violate
any other part of the standard in the process.

[ ... ]

> >struct A {
> >public: int x;
> >public: int y;
> >public: int z;
> >};

[ ... ]

> And I think that a struct (or class) with multiple declarative regions
> for data members should not be classified as a POD.

I'm not sure I agree. One reason for the rules about PODs is to
allow C and C++ files that use common headers to link together and
use the same struct layouts. Clearly including ANY access specifier
renders this a moot point, since they're not legal in C declarations
(they'd be interpreted as labels, which I'm reasonably certain aren't
allowed in struct declarations).

If I'm not mistaken, you should also be able to do a bitwise copy of
one POD to a compatible POD and get defined results. Including an
access specifier doesn't automatically negate this. I can see some
arguments in both directions here. On one hand, giving an access
specifier that _looks_ vacuous a meaning that's not even remotely
related to access seems like a rather poor idea. OTOH, most of the
time the access specifier has that meaning anyway.

I'm generally in favor of giving the compiler as much latitude as
possible to help it produce better code. At the same time, I'm hard
put to come up with a good reason to believe that rearranging a few
elements in a struct is really likely to make any huge difference;
this isn't exactly a new technology area where great new technology
is happening on a regular basis.

As such, I'm not sure what's really gained by restricting PODs in
this fashion.

> Should we raise an issue (potential DR) on this.

I agree that things really aren't very good the way they are -- the
rules are confusing enough that I'm still not sure I reached the
right conclusion, even right after looking at the standard. I think
it's safe to say that six months from now I won't know them without
looking at the standard again. I also certainly can't provide any
reasonable explanation for _why_ the example I gave should really be
treated differently than the one you gave.

I'm a bit less certain about what resolution to suggest though. One
obvious possibility would be the one you gave: something is only a
POD struct if it contains at most one access specifier, which must
precede all declarations of non-static members. Another possibility
would be to amend 9.2/12 to apply only to structs of non-POD type.

Personally, I _tend_ to favor the latter, but only by a very slight
margin. Most of my reasoning is fairly simple: POD-structs tend to
matter the most to people mixing C and C++. This often happens when
people are in the process of switching from C to C++. Expecting such
a person to learn an esoteric rule about a far-from-obvious meaning
of an access specifier right away seems (at least to me) like little
more than an unnecessary road-block.

--
Later,
Jerry.

The universe is a figment of its own imagination.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ray Lischner

unread,
Nov 21, 2002, 6:48:10 AM11/21/02
to
On Wednesday 20 November 2002 08:47 am, Jerry Coffin wrote:

> As such, I'm not sure what's really gained by restricting PODs in

> this fashion....POD-structs tend to


> matter the most to people mixing C and C++.

Consider 9.5 (unions).

"If a POD-union contains several POD-struts that share a common initial
sequence (9.2), and if an object of this POD-union type contains one of
the POD-structs, it is permitted to inspect the common initial sequence
of any of POD-struct members; see 9.2"

Obviously, this works only if the POD-structs do not have any access
specifier labels in the common initial sequence. This problem has
nothing to do with C compatibility.
--
Ray Lischner, author of C++ in a Nutshell (forthcoming)
http://www.tempest-sw.com/cpp/

Anthony Williams

unread,
Nov 21, 2002, 7:01:39 AM11/21/02
to
Jerry Coffin <jco...@taeus.com> writes:

[snipped discussion of whether or not an access specifier negates POD-ness]

> POD-structs tend to
> matter the most to people mixing C and C++.

POD-structs also have magical properties, like the ability to be statically
initialized, memcpy'd around, or even left uninitialized, which make them
useful for people dealing exlusively with C++, too.

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

Francis Glassborow

unread,
Nov 21, 2002, 12:22:06 PM11/21/02
to
In message <MPG.18437d8bb...@news.direcpc.com>, Jerry Coffin
<jco...@taeus.com> writes

> > Should we raise an issue (potential DR) on this.
>
>I agree that things really aren't very good the way they are -- the
>rules are confusing enough that I'm still not sure I reached the
>right conclusion, even right after looking at the standard. I think
>it's safe to say that six months from now I won't know them without
>looking at the standard again. I also certainly can't provide any
>reasonable explanation for _why_ the example I gave should really be
>treated differently than the one you gave.
>
>I'm a bit less certain about what resolution to suggest though. One
>obvious possibility would be the one you gave: something is only a
>POD struct if it contains at most one access specifier, which must
>precede all declarations of non-static members. Another possibility
>would be to amend 9.2/12 to apply only to structs of non-POD type.
>
>Personally, I _tend_ to favor the latter, but only by a very slight
>margin. Most of my reasoning is fairly simple: POD-structs tend to
>matter the most to people mixing C and C++. This often happens when
>people are in the process of switching from C to C++. Expecting such
>a person to learn an esoteric rule about a far-from-obvious meaning
>of an access specifier right away seems (at least to me) like little
>more than an unnecessary road-block.

I think it very unlikely that a newcomer to C++ would think about using
multiple access specifiers for data, particularly as all data must be
public in a POD so the problem only occurs if the programmer uses
multiple 'public' access qualifiers.

What we have at the moment is that multiple public access specifiers do
allow some re-ordering even in a POD type, and that contravenes the
intent (to define types that are layout compatible with C types)


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Nov 22, 2002, 8:35:16 PM11/22/02
to
In message <57cb.3ddb...@prospero.island.local>, Ray Lischner
<donts...@spam.you> writes

>Obviously, this works only if the POD-structs do not have any access
>specifier labels in the common initial sequence. This problem has
>nothing to do with C compatibility.


Except that the entire issue of PODs is to do with C Compatibility and
in particular the license to inspect the shared initial sequence.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ray Lischner

unread,
Nov 23, 2002, 8:22:14 AM11/23/02
to
On Friday 22 November 2002 05:35 pm, Francis Glassborow wrote:

> In message <57cb.3ddb...@prospero.island.local>, Ray Lischner

>>Obviously, this works only if the POD-structs do not have any access
>>specifier labels in the common initial sequence. This problem has
>>nothing to do with C compatibility.
>
> Except that the entire issue of PODs is to do with C Compatibility and
> in particular the license to inspect the shared initial sequence.

Pardon me for being dense, but I don't understand your point. I agree
that the main issue of PODs is C compatibility, but my argument is that
the issue is somewhat broader than that, and I cited an example where
the problem of access specifier labels and PODs has an impact without
bringing C compatibility into the picture.

I brought this up over a month ago, but the discussion fizzled. I agree
with you that there should be a DR on this. I haven't had the time to
formulate a coherent report yet.


--
Ray Lischner, author of C++ in a Nutshell (forthcoming)
http://www.tempest-sw.com/cpp/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jerry Coffin

unread,
Nov 24, 2002, 6:35:01 AM11/24/02
to
In article <57cb.3ddb...@prospero.island.local>,
donts...@spam.you says...

[ ... ]

> Consider 9.5 (unions).
>
> "If a POD-union contains several POD-struts that share a common initial
> sequence (9.2), and if an object of this POD-union type contains one of
> the POD-structs, it is permitted to inspect the common initial sequence
> of any of POD-struct members; see 9.2"
>
> Obviously, this works only if the POD-structs do not have any access
> specifier labels in the common initial sequence. This problem has
> nothing to do with C compatibility.

I'm forced to disagree: if C compatibility wasn't a concern, I doubt
that there would be such a thing as a union to start with. Instead,
you'd simply use inheritance, and the common initial sequence would
be the members of the base class.

I'm not sure there's any restrict on there being on access specifiers
in the common initial sequence (I can't find any) so this may be
enough to prevent the compiler from rearranging members of a POD,
even though 9.2/12 says it should be able to -- at least most of the
time, the compiler can't tell when/if you might create a union that
includes this struct, and any or all members of the struct might be
part of a common initial sequence with some other struct that didn't
include any access specifiers, so they have to be arranged in the
same order, and they weren't allowed to be rearranged in the other
struct, so they can't in one with access specifiers either.

Given the convoluted path it takes to get to this conclusion,
however, I'm more convinced than ever that this really needs to be
written up for a DR, but I'm less certain than ever of what to
propose as a solution.

--
Later,
Jerry.

The universe is a figment of its own imagination.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Nov 24, 2002, 3:28:44 PM11/24/02
to
In message <6cf5.3dde...@prospero.island.local>, Ray Lischner
<donts...@spam.you> writes

>On Friday 22 November 2002 05:35 pm, Francis Glassborow wrote:
>
> > In message <57cb.3ddb...@prospero.island.local>, Ray Lischner
>> >Obviously, this works only if the POD-structs do not have any access

>> >specifier labels in the common initial sequence. This problem has
>> >nothing to do with C compatibility.
> >
> > Except that the entire issue of PODs is to do with C Compatibility
> > and in particular the license to inspect the shared initial
> > sequence.
>
>Pardon me for being dense, but I don't understand your point. I agree
>that the main issue of PODs is C compatibility, but my argument is that

>the issue is somewhat broader than that, and I cited an example where
>the problem of access specifier labels and PODs has an impact without
>bringing C compatibility into the picture.

I think the confusion is that you are looking at the issues that arise
today within C++ even without linking code to C code, or requiring that
the code can be compiled as C as well as C++ (but then access specifiers

go out the window) I am looking at why these issues arise in C++ at all.

Had we not had to design for C compatibility I doubt that we would have
concerned our selves with such things as common start sequences shared
by members of a union.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Sean Kelly

unread,
Nov 28, 2002, 6:12:30 PM11/28/02
to
Francis Glassborow wrote:
>
> I think it very unlikely that a newcomer to C++ would think about using
> multiple access specifiers for data, particularly as all data must be
> public in a POD so the problem only occurs if the programmer uses
> multiple 'public' access qualifiers.
>
> What we have at the moment is that multiple public access specifiers do
> allow some re-ordering even in a POD type, and that contravenes the
> intent (to define types that are layout compatible with C types)

I'm going to ask another question, then, that concerns another common
method of C/C++ POD compatibility: subclassing. What about this:

struct A {
int x;
float y;
};

struct B : public A {
private:
double z;
};

What are the rules governing whether a B can successfully be converted
to an A when passing it to an extern "C" function? I would assume that
casting likely won't rearrange member order. Is the inheriting from a
POD type enough to gurantee that the order of data inherited from the
POD class is guranteed?


Sean

Francis Glassborow

unread,
Nov 30, 2002, 1:53:45 PM11/30/02
to
In message <JF6F9.4901$GG1.26...@newssvr13.news.prodigy.com>, Sean
Kelly <ken...@pacbell.net> writes

>I'm going to ask another question, then, that concerns another common
>method of C/C++ POD compatibility: subclassing. What about this:
>
>struct A {
> int x;
> float y;
>};

Well that is a POD so we have some guarantees about layout.

>
>struct B : public A {
>private:
> double z;
>};
>
>What are the rules governing whether a B can successfully be converted
>to an A when passing it to an extern "C" function?

The only way you could pass it to a C function would be by value. That
means that the A part of a B object will be copied (and so sliced). The
result will be that you have an ordinary A object.

Well it isn't quite the only way because you could use an A* and that
answers your underlying question. As there are no virtual functions
lying around (and so supporting typeinfo) the compiler must be able to
get the right behaviour from an A* without knowing if it points to an A
object or to one derived from an A object.

> I would assume that
>casting likely won't rearrange member order. Is the inheriting from a
>POD type enough to gurantee that the order of data inherited from the
>POD class is guranteed?

--

Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

0 new messages