struct alignment

M

Mark

Hello:

#define MAX_SIZE 8

enum my_enum
{
VAL1 = 0;
VAL2,
VAL3,
VAL4,
VAL_MAX
};

struct my_struct
{
enum my_enum e;
int w[MAX_SIZE];
};

Can a layout in such structure cause alignment issues on a target platform?
I understand it much depends on a platform, but generally C compiler is
allowed to do padding of structures, so for example on 32 bit machine, where
'int' is 32 bit long:

struct my_struct
{
int w[MAX_SIZE];
}

is aligned (as fas as I understand) so compiler probably won't be doing
anything else with its layout, but adding 'enum my_enum' in the structure
can poptentially get the structure un-aligned on such machine. Should I be
doing anything special to avoid this and should I be avoiding it at all ?

Would be very thankful for clarifications!

Mark
 
K

Kleuske

Hello:

#define MAX_SIZE 8

enum my_enum
{
VAL1 = 0;
VAL2,
VAL3,
VAL4,
VAL_MAX
};

struct my_struct
{
enum my_enum e;
int w[MAX_SIZE];
};

Can a layout in such structure cause alignment issues on a target
platform? I understand it much depends on a platform, but generally C
compiler is allowed to do padding of structures, so for example on 32
bit machine, where 'int' is 32 bit long:

struct my_struct
{
int w[MAX_SIZE];
}

is aligned (as fas as I understand) so compiler probably won't be doing
anything else with its layout, but adding 'enum my_enum' in the
structure can poptentially get the structure un-aligned on such machine.
Should I be doing anything special to avoid this and should I be
avoiding it at all ?

Would be very thankful for clarifications!

Mark

In general you should not rely on things being padded or not. Not only can
it differ on different machines, it can differ for different settings of the
same compiler.

Behind the scenes, an enum is treated like an integer and the same issues can
arise. If your code depends on things being padded this or that way or not at
all, start thinking about ways of doing it differently.
 
R

Ralf Damaschke

Mark said:
Can a layout in such structure cause alignment issues on a target
platform? I understand it much depends on a platform, but generally
C compiler is allowed to do padding of structures, so for example
on 32 bit machine, where 'int' is 32 bit long:

struct my_struct
{
int w[MAX_SIZE];
}

is aligned (as fas as I understand) so compiler probably won't
be doing anything else with its layout, but adding 'enum
my_enum' in the structure can poptentially get the structure
un-aligned on such machine. Should I be doing anything special
to avoid this and should I be avoiding it at all ?

No, you don't need to care. Each structure member will be aligned
according to its own requirements and the whole structure will meet
these requirements, too (as long as esp. for malloc()ed memory the
returned pointer has not been changed "unalignedly" later by the
program).

-- Ralf
 
K

Keith Thompson

Mark said:
#define MAX_SIZE 8

enum my_enum
{
VAL1 = 0;
VAL2,
VAL3,
VAL4,
VAL_MAX
};

struct my_struct
{
enum my_enum e;
int w[MAX_SIZE];
};

Can a layout in such structure cause alignment issues on a target platform?
I understand it much depends on a platform, but generally C compiler is
allowed to do padding of structures, so for example on 32 bit machine, where
'int' is 32 bit long:

struct my_struct
{
int w[MAX_SIZE];
}

is aligned (as fas as I understand) so compiler probably won't be doing
anything else with its layout, but adding 'enum my_enum' in the structure
can poptentially get the structure un-aligned on such machine. Should I be
doing anything special to avoid this and should I be avoiding it at all ?

The compiler will (in fact, it *must*) insert whatever padding is
necessary so that all the members can be accesssed correctly. It may or
may not insert more padding than it strictly needs to.

The language standard guarantees that the first declared member is at
offset 0, and that all other members are at increasing offsets in the
order in which they're declared (the compiler can't rearrange members).
There can be arbitrary padding between members, or after the last one.

Some compilers have extensions that allow you to request tighter packing
(less padding) than the default. In at least one case, such an
extension can cause serious problems on some platforms; see:
http://stackoverflow.com/questions/8568432/
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628

But if just let the compiler do its job and write portable code (and
don't make assumptions about padding), there shouldn't be any problems.
 
D

Dr Nick

Keith Thompson said:
The compiler will (in fact, it *must*) insert whatever padding is
necessary so that all the members can be accesssed correctly. It may or
may not insert more padding than it strictly needs to.

The language standard guarantees that the first declared member is at
offset 0, and that all other members are at increasing offsets in the
order in which they're declared (the compiler can't rearrange
members).

Does any compiler let you do this? I have done things where the order
of a least some elements (usually the first or the last) matters, but
it's rare.
There can be arbitrary padding between members, or after the last one.

Some compilers have extensions that allow you to request tighter packing
(less padding) than the default.

I can think of cases where re-arranging could give significant space
savings without these risks.

In response to the obvious "why don't you do it?" there are a couple of
reasons. One, of course, that it will vary from platform to platform.
The second is that quite often there is a logical order or partial order
of fields from a program logic point of view that is different to the
most efficient.

For example, you might want to start off with a small integer to say
what type of object you have, have a few pointers that point to various
type-specific things, then an integer reference count and then a pointer
to the next one in a list.

Shoving the two integers together could well save you some memory with
out the need for the compiler to generate fancy code (as in the "packed"
case) but at the loss of program source clarity.
 
I

Ian Collins

Does any compiler let you do this? I have done things where the order
of a least some elements (usually the first or the last) matters, but
it's rare.

Let you do what? I didn't see anything optional in Keith's reply.
 
K

Keith Thompson

Ian Collins said:
Let you do what? I didn't see anything optional in Keith's reply.

Permit reordering of struct members, I presume. Plenty of C
compilers have plenty of options that break standard compliance.

For that matter, let me back off slightly from my statement above. A
conforming C compiler could provide an implementation-defined #pragma
directive that permits arbitrary reordering of struct members (for size
minimization, for example). C99 6.10.6p1 says that a #pragma directive:

causes the implementation to behave in an implementation-defined
manner. The behavior might cause translation to fail or
cause the translator or the resulting program to behave in a
non-conforming manner.

So a hypothetic implementation might have:

struct reordered {
#pragma REORDER_STRUCT_MEMBERS
char c0;
char c1;
int i;
};

that could put i at offset 0, followed by c0 and c1.

But I've never heard of a C compiler that actually does this.

<OT>I've worked on an Ada compiler that did the equivalent of reordering
struct members, but the Ada standard doesn't require members to be
allocated in declared order.<?OT>
 
J

Jorgen Grahn

Permit reordering of struct members, I presume. Plenty of C
compilers have plenty of options that break standard compliance.

But is it really breaking compliance?

struct Foo {
int a;
char b;
int c;
char d;
};

If the compiler lays these out as a-c-b-d, is that really something
which is observable using correct C code?

I seem to recall (but I can be wrong) that the expression
&foo.b < &foo.d is not guaranteed to be meaningful, unlike e.g.
comparisons inside an array.

/Jorgen
 
K

Kaz Kylheku

But is it really breaking compliance?

struct Foo {
int a;
char b;
int c;
char d;
};

If the compiler lays these out as a-c-b-d, is that really something
which is observable using correct C code?

I seem to recall (but I can be wrong) that the expression
&foo.b < &foo.d is not guaranteed to be meaningful, unlike e.g.
comparisons inside an array.

C has an offsetof macro, such that offsetof(struct Foo, a) == 0 has to hold,
and the offsets of the other members have to be in increasing order.

Reordering struct members would break all kinds of code, not all of which is
ISO C mandated.

For instance maintaining backward binary compatibility in shared library
interfaces for structures that are allocated outside of the library
(e.g. in static or automatic storage in client code).

/* Maintainers! Add new members only at the end. */
struct Foo {
int a; /* Lib 1.0 members */
char b;
int c; /* Added in 1.2 */
char d; /* New in 1.3 */
};

In this case, the above struct has to be compatible with the one
compiled in the existing 1.0 clients which is just this:

struct Foo {
int a; /* Lib 1.0 members */
char b;
};

(Knowledge about which type of client is attached to the library can be used to
carefully avoid touching members c and d.)

Sometimes structs are used to conform to an external storage layout,
or hardware registers.
 
S

Stephen Sprunk

But is it really breaking compliance?

struct Foo {
int a;
char b;
int c;
char d;
};

If the compiler lays these out as a-c-b-d, is that really something
which is observable using correct C code?

Yes, using offsetof(). And there are plenty of cases where this
actually matters in real-world code.
I seem to recall (but I can be wrong) that the expression
&foo.b < &foo.d is not guaranteed to be meaningful, unlike e.g.
comparisons inside an array.

It's guaranteed to be meaningful.

N1256, 6.5.8.5:
"If the objects pointed to are members of the same aggregate object,
pointers to structure members declared later compare greater than
pointers to members declared earlier in the structure, ..."

Reordering structure members is therefore a constraint violation, and
any compiler that does it is non-compliant.

S
 
K

Keith Thompson

Stephen Sprunk said:
Reordering structure members is therefore a constraint violation, and
any compiler that does it is non-compliant.

A "constraint violation" is an error in code. Errors in compilers are
just bugs.
 
J

Jorgen Grahn

It's also required that structures with common leading sections have
the same in-storage layout.

Ok, that is enough reason for not allowing reordering. To me, the
real reason then seems to be to allow things like the POSIX struct
sockaddr/sockaddr_in/sockaddr_in6/... hack. I always assumed the
sockaddr stuff demanded stronger guarantees from the compiler than the
standard gives.
Of course that's all subject to the as-if rule, if the compiler can
determine that the program never looks at the ordering, or the
compiler can fake it, it's allowed to do anything it wants under the
covers, including omitting and reordering parts or all of the
structure.

Yes, but that surely is rare. :-( Most structs are not limited to one
translation unit.

I agree with whoever-it-was upthread: if it was allowed to do it, the
compiler could do a much better layout of my structs than I am willing
to do manually.

/Jorgen
 
J

Joe keane

Reordering struct members would break all kinds of code, not all of which is
ISO C mandated.

It would be a cool option though...

struct apple
{
char x;
double y;
};

struct vector
{
__rearrangeok
struct apple e[5];
};

->

struct vectorn
{
char exz[5];
double eyz[5];
};
 
B

Ben Pfaff

It would be a cool option though...

C++ has something a little like this. If you write "public:"
between each pair of members, then the compiler is allowed to
arrange them the members in any order, except that (based on a
quick reading, anyway) the first member declared still has to be
first.
 
J

Jorgen Grahn

Perhaps not so rare - a common case occurs when a (small-ish)
structure is passed to or returned from a function that gets inlined.
In C++ you see that in a lot of implicitly generated temporaries. Two
cases in particular I've seen are in some graphics code where a
"point" or "pixel" structure was so treated, and in code with a
"complex" structure for representing, *ahem*, complex numbers. Of
course none of those examples would typically involve any alignment
issues.

True, and that is a case where I assume the compiler does something
smart. I automatically assume that in C too, but perhaps that's due
to my C++ training.

[...]

/Jorgen
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top