struct and union alignment

S

S.Tobias

I would like to check if I understand the following excerpt correctly:

6.2.5#26 (Types):
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types shall
have the same representation and alignment requirements as each other.

Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?


If the answer to the above is "yes", then it means that:

1. Alignment of any struct (union) must be maximum or its multiple.
(Alignment of a struct (union) can't be less restrictive than that
of its members[*]. Since any (object) type may be a member, at
least one struct (union) must have at least that type's alignment.
Since all struct (union) types have the same alignment,
it follows that all must meet the the maximum one.)

2. Alignment requirements for all structs _and_ unions are the same.
(Since you can have a struct as a member of a union, and a union as a
member of a struct, it follows that their alignments must be the same).

[*] During google search I have learned that a type's alignments
may differ in a struct and outside. Here I rather mean the least
restrictive alignment requirement for a type that has to be met
for a particular architecture.
 
K

Keith Thompson

S.Tobias said:
I would like to check if I understand the following excerpt correctly:

6.2.5#26 (Types):
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types shall
have the same representation and alignment requirements as each other.

Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

No, it's referring to the alignment of the pointer, not the alignment
of the struct or union.
 
F

Flash Gordon

I would like to check if I understand the following excerpt correctly:

6.2.5#26 (Types):
All pointers to structure types shall have the same representation
and alignment requirements as each other. All pointers to union
types shall have the same representation and alignment requirements
as each other.

Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

Yes. Think about what what has to be done to implement pointers to
anonymous structs. When the compiler is compiling a piece of code that
increments a pointer to an anonymous struct all it knows is that it is a
pointer to a struct, so how else could this have been done?
If the answer to the above is "yes", then it means that:

1. Alignment of any struct (union) must be maximum or its multiple.
(Alignment of a struct (union) can't be less restrictive than that
of its members[*]. Since any (object) type may be a member, at
least one struct (union) must have at least that type's alignment.
Since all struct (union) types have the same alignment,
it follows that all must meet the the maximum one.)
Yes.

2. Alignment requirements for all structs _and_ unions are the same.
(Since you can have a struct as a member of a union, and a union as
a member of a struct, it follows that their alignments must be the
same).

Sounds logical to me.
[*] During google search I have learned that a type's alignments
may differ in a struct and outside. Here I rather mean the least
restrictive alignment requirement for a type that has to be met
for a particular architecture.

The alignment inside a struct is at least as strict as outside, since
you can take a pointer to an element in a struct. However, yes, I
can't think of anything that would prevent the compiler from padding
things out further.
 
S

S.Tobias

No, it's referring to the alignment of the pointer, not the alignment
of the struct or union.

What's the difference?

Strictly speaking, (complete) _types_ have alignment requirements.
As I understand it, when we say "a pointer to TYPE has alignment
requirements", we mean exactly same thing as: "TYPE has alignment
requirements"; I don't see any reason to differentiate between these two.

(I have also considered "pointer to struct" type (ie.: struct s *)
alignment requirements, but this doesn't make sense in context of
the quoted part of the Standard.)
 
K

Keith Thompson

Flash Gordon said:
I would like to check if I understand the following excerpt correctly:

6.2.5#26 (Types):
All pointers to structure types shall have the same representation
and alignment requirements as each other. All pointers to union
types shall have the same representation and alignment requirements
as each other.

Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

Yes. Think about what what has to be done to implement pointers to
anonymous structs. When the compiler is compiling a piece of code that
increments a pointer to an anonymous struct all it knows is that it is a
pointer to a struct, so how else could this have been done?

When 6.2.5 discusses the alignment requirements of various types, it's
clear that it's referring to the alignment of objects of the type
itself. It uses similar wording in 6.2.5p26, so I think it's
referring to the alignment of a pointer object, not the alignment of
what it points to.

I don't think this is a problem for pointers to anonymous structs.
You can't create a pointer value that points to an anonymous struct
without knowing what the actual type is. Similarly, you can't
increment a pointer to an anonymous struct without knowing the
struct's size.

I believe that an implementation in which pointer values are simple
byte addresses, small structs (struct { char c; }) have, say, 1-byte
alignment, and larger structs have, say, 4-byte alignment could be
conforming. Can you think of a concrete example where this would
cause problems?

[...]
[*] During google search I have learned that a type's alignments
may differ in a struct and outside. Here I rather mean the least
restrictive alignment requirement for a type that has to be met
for a particular architecture.

The alignment inside a struct is at least as strict as outside, since
you can take a pointer to an element in a struct. However, yes, I
can't think of anything that would prevent the compiler from padding
things out further.

Assume in the following that sizeof(int) == 4.

On some hardware, an int can be accessed more efficiently if it's
aligned on a 4-byte boundary, but can still be accessed if it's merely
byte-aligned. An implementation could consistently choose to align
all declared int objects on 4-byte boundary, but use byte alignment
for struct members that are of type int (to save space). Or vice
versa.

I'm not saying that this would be a sensible thing to do, but it's
legal.

I suppose we're talking about two different meanings of "alignment
requirements": the alignment the compiler chooses to use for a given
type, and the alignment that's actually required by the hardware. The
former needs to be at least as strict as the latter, but it needn't be
the same.
 
S

S.Tobias

Flash Gordon said:
On 23 Sep 2004 19:10:38 GMT
Yes. Think about what what has to be done to implement pointers to
anonymous structs. When the compiler is compiling a piece of code that
increments a pointer to an anonymous struct all it knows is that it is a
pointer to a struct, so how else could this have been done?

I'm sorry, but I can't see how can you define a pointer to anonymous
struct in the first place (since that struct has no name). And how
that could relate to alignment issues (incrementing a pointer has
at most to do with type size, not alignment).

[ C Std doesn't define anonymous structs. I've found somewhere the
anonymous structs are structs "declared" within other structs/unions,
that don't have a tag, object nor typedef name. ]

[*] During google search I have learned that a type's alignments
may differ in a struct and outside.
The alignment inside a struct is at least as strict as outside, since
you can take a pointer to an element in a struct. However, yes, I
can't think of anything that would prevent the compiler from padding
things out further.

I read someone saying that alignment requirements inside a struct might
be even less restrictive than outside (I've lost that post, but when I
find it I'll post it here). The explanation was like this: for example
a 32-bit int may have 2-byte alignment requirement, but if it's on 4-byte
boundary it's accessed faster. So an implementation might have 4-byte
int alignment outside structs, but for better packing reasons 2-byte
alignment inside.
 
K

Keith Thompson

S.Tobias said:
What's the difference?

Strictly speaking, (complete) _types_ have alignment requirements.
As I understand it, when we say "a pointer to TYPE has alignment
requirements", we mean exactly same thing as: "TYPE has alignment
requirements"; I don't see any reason to differentiate between these two.

It's just like the difference between the size of a pointer and the
size of what it points to.

For example, a pointer object might require 4-byte alignment, whereas
a char object requires only 1-byte alignment. When the standard says
void* and char* have to have the same alignment requirements, the
intent is that they're interchangeable as arguments to functions.
Requiring 1-byte alignment for char* but only 4-byte alignment for
void* could break this.

Look at the other references to alignment requirements in 6.2.5; they
clearly refer to the alignment of the type itself. 6.2.5#26 uses
similar wording, so it refers to the alignment of the pointers
themselves. (Alignment requirements for character types are discussed
elsewhere.)
 
M

Mabden

Flash Gordon said:
Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

Unions also have the caveat that they be aligned according to the most
restrictive item in the union. So a struct {char a; double z;} could
have a different alignment than union {char a; double z;}.
 
B

Barry Schwarz

What's the difference?

Strictly speaking, (complete) _types_ have alignment requirements.
As I understand it, when we say "a pointer to TYPE has alignment
requirements", we mean exactly same thing as: "TYPE has alignment
requirements"; I don't see any reason to differentiate between these two.

Actually, this is informally speaking, not strictly speaking.
Informally, some talk about aligning a pointer when we really mean
aligning the *VALUE* assigned to the pointer which is equivalent to
aligning the object the pointer points to.

Strictly speaking, when we talk about aligning a pointer we mean
aligning the pointer itself.

For example, on my system all pointers require four-byte alignment
while doubles require eight-byte alignment. A pointer to double need
only be aligned on a four-byte boundary but its value better be
aligned on an eight-byte boundary.
(I have also considered "pointer to struct" type (ie.: struct s *)
alignment requirements, but this doesn't make sense in context of
the quoted part of the Standard.)

Actually it does. If we have a number of different structs, some with
one-byte alignment, some with two, some with four, and some with
eight, a set of pointers to these different structs all have the same
alignment (four-byte on my system) and representation, even though the
objects they point to (and therefore the values they contain) have
different requirements.

Just as note, this is what allows a struct type to contain a member
which is a pointer to the same struct type (think linked list). At
the time the member is being processed by the compiler, the alignment
requirements of the struct are not yet known (the struct is still
incomplete) but the alignment requirements of the pointer are known so
the compiler can decide how much padding is needed.


<<Remove the del for email>>
 
B

Barry Schwarz

I would like to check if I understand the following excerpt correctly:

6.2.5#26 (Types):
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types shall
have the same representation and alignment requirements as each other.

Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

No. It is only talking about the pointers themselves and not about
the values assigned to the pointers or the objects the pointers point
to.
If the answer to the above is "yes", then it means that:

1. Alignment of any struct (union) must be maximum or its multiple.
(Alignment of a struct (union) can't be less restrictive than that
of its members[*]. Since any (object) type may be a member, at
least one struct (union) must have at least that type's alignment.
Since all struct (union) types have the same alignment,
it follows that all must meet the the maximum one.)

Since the answer is no, the conclusion is unwarranted.
2. Alignment requirements for all structs _and_ unions are the same.
(Since you can have a struct as a member of a union, and a union as a
member of a struct, it follows that their alignments must be the same).
Ditto.


[*] During google search I have learned that a type's alignments
may differ in a struct and outside. Here I rather mean the least
restrictive alignment requirement for a type that has to be met
for a particular architecture.

I don't think so in standard C. It may be possible with some compiler
specific extensions (e.g., some have an option to eliminate padding).


<<Remove the del for email>>
 
K

Keith Thompson

Mabden said:
Flash Gordon said:
Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

Unions also have the caveat that they be aligned according to the most
restrictive item in the union. So a struct {char a; double z;} could
have a different alignment than union {char a; double z;}.

Both unions and structs have to be aligned at least as strictly as
their most strictly aligned member. Both struct {char a; double z;}
and union {char a; double z;} have to be aligned in a way that allows
the 'z' member to be accessed. (This can require padding between
members, and possibly after the last member, for a struct; any padding
in a union occurs after each member, since all members have the same
offset.)
 
C

Christian Kandeler

S.Tobias said:
I'm sorry, but I can't see how can you define a pointer to anonymous
struct in the first place (since that struct has no name).

struct {
int a;
int b;
} *pointer_to_anonymous_struct;


Christian
 
S

S.Tobias

Keith Thompson said:
For example, a pointer object might require 4-byte alignment, whereas
a char object requires only 1-byte alignment. When the standard says
void* and char* have to have the same alignment requirements, the
intent is that they're interchangeable as arguments to functions.

Right.
extern char *pc;
void free(void *p);
free(pc); //correct

(Note: we don't need same representation requirement in the above
example. This requirement is necessary eg. for variadic arguments:
printf("%p", pc);
- no cast to void* required.)
Requiring 1-byte alignment for char* but only 4-byte alignment for
void* could break this.

No. I see no reason to require same alignment for types void* and char*,
because in function arguments they're passed by *value* (think conversion).
Similarly, long and char do not have to have same alignment, but we may
always use them in arguments "interchangeably":
extern long l;
extern char c;
int f_char(unsigned char c);
int f_long(unsigned long l);
f_char(l); //both calls correct
f_long(c);

Look at the other references to alignment requirements in 6.2.5; they
clearly refer to the alignment of the type itself. 6.2.5#26 uses
similar wording, so it refers to the alignment of the pointers
themselves. (Alignment requirements for character types are discussed
elsewhere.)

I have looked in the entire text. The Standard uses the word "alignment"
in three ways: type (or object) alignment; pointer value alignment
(it uses words: "value", "result", "address"); or pointer alignment
(the way we discuss now).

The last manner is also found in: 6.3.2.3#7 (Pointers) and 7.20.3#1
(Memory management functions). See for yourself: in both cases "pointer
alignment" refers to the pointer *value*, not pointer type.


Actually, this is informally speaking, not strictly speaking.
Informally, some talk about aligning a pointer when we really mean
aligning the *VALUE* assigned to the pointer which is equivalent to
aligning the object the pointer points to.
Strictly speaking, when we talk about aligning a pointer we mean
aligning the pointer itself.

So this is actually what you and Keith think the Standard refers to!
So the fight is over "strictly" and "informally". I think that
the Standard in all cases means "informally".

Just as note, this is what allows a struct type to contain a member
which is a pointer to the same struct type (think linked list). At
the time the member is being processed by the compiler, the alignment
requirements of the struct are not yet known (the struct is still
incomplete) but the alignment requirements of the pointer are known so
the compiler can decide how much padding is needed.

While this might be a problem, I agree, this is an internal matter
of the implementation how it solves this (pointer type alignment and
padding before it). The Standard is a contract between an implementor
and a programmer. There is nothing a programmer can gain from
knowing that all pointer-to-struct types have same alignment and
thanks to it the compiler can easily construct a structure type.
I just think your argument misses the point.

OT:
The compiler might construct a struct type in several passes, each
time adjusting the padding before the pointer member.
This process must end, because there exists a maximum alignment.


========

My arguments:


6.2.5#26 (extended quote, to get more context)
A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type.39) Similarly,
pointers to qualified or unqualified versions of compatible types
shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types
shall have the same representation and alignment requirements
as each other. Pointers to other types need not have the same
representation or alignment requirements.

39) The same representation and alignment requirements are meant
to imply interchangeability as arguments to functions, return
values from functions, and members of unions.

Rationale:
[...] A pointer to void must have the same representation
and alignment as a pointer to char; the intent of this rule is
to allow existing programs that call library functions such as
memcpy and free to continue to work.

Remark: It is obvious the Standard means "pointers to (structure types)",
not "(pointers to structure) types". This follows from English grammar
rules, but please don't ask me for chapter and verse! :)

The first part the Std talks about the "compatibility" of void* and char*
types. Here it definitely refers to alignment of pointer *values*.
This is required for conversions between void* and char* to be well
defined. Of course, the Std cannot say directly about requirements
for the types they point to, because void is not a complete type (but
this is the intention if we forget it for a while and treat void as an
integer type with size one, but not compatible with char).
(OTOH the Std could formally define alignment of void type to be equal
to that of char type.)

The Standard cannot refer to the alignment of _types_ void* and char*.
If it did, it would only concern conversions between void** and char**.
The only standard functions with that type are strto?() family and friends
(and then we should add same requirement for wchar_t* to be consistent).
The rationale mentions only functions like free() or memcpy(), ie. ones
that probably historically had int free(char*) prototypes before the
type void was introduced. Here, the alignment compatibility between
the _values_ of type void* and char* is essential - IOW it means the
resolution of void* and char* pointer types is the highest and both
are equivalent in this matter.

Then, after the word "Similarly", the Standard talks about alignment
of pointers to compatible types, struct and unions, and other types in
the same manner. There is no reason to believe it uses similar wording
in a different manner this time.

There is no advantage in guaranteeing same alignment for "pointers
to incompatible types" types (at least I can't think of any).
All of them can be stored as void* if need be.
 
S

S.Tobias

Christian Kandeler said:
S.Tobias wrote:
struct {
int a;
int b;
} *pointer_to_anonymous_struct;

OIC, didn't think of that.

But then again, what would be a use for that? Since
this is not a struct object definition, there are no objects
of type pointer_to_anonymous_struct points to.

Mmmm, could it be:
pointer_to_anonymous_struct = malloc(sizeof *pointer_to_anonymous_struct);
?
But what is the point in having an anonymous struct then?

Could you supply a real-life example?
 
S

Simon Stienen

S.Tobias said:
OIC, didn't think of that.

But then again, what would be a use for that? Since
this is not a struct object definition, there are no objects
of type pointer_to_anonymous_struct points to.

Mmmm, could it be:
pointer_to_anonymous_struct = malloc(sizeof *pointer_to_anonymous_struct);
?
But what is the point in having an anonymous struct then?

Could you supply a real-life example?

Maybe something like:

int main() {
uint32 x = 0x5678abcd;
struct {
uint16 hiword;
uint16 loword;
} *wordsinlong = &x;
printf("Hiword: %x\nLoword: %x",
words_in_long->hiword,
words_in_long->loword);
return 0;
}
 
D

Dan Pop

In said:
What's the difference?

If you can't grasp the difference between a pointer and the pointed-to
object, stop messing with the C standard and read K&R2 (again).

Dan
 
X

xarax

Mabden said:
Flash Gordon said:
Does it mean that *all* structure (or union) types have the same
alignment?
Eg. type
struct { char c; }
and
struct { long double ldt[11]; }
have the same alignment requirements?

Unions also have the caveat that they be aligned according to the most
restrictive item in the union. So a struct {char a; double z;} could
have a different alignment than union {char a; double z;}.

Wrong. Both the struct and union have the same
alignment as double. A struct's alignment is
the same as the strictest (widest) alignment
of any of its members, including nested aggregates.
Same rules apply for union. The alignment is that
of the strictest alignment of any of its members,
including nested aggregates (other unions or
structs).

Maybe you are confusing the size with alignment?
 
D

Dan Pop

In said:
OIC, didn't think of that.

But then again, what would be a use for that? Since
this is not a struct object definition, there are no objects
of type pointer_to_anonymous_struct points to.

Mmmm, could it be:
pointer_to_anonymous_struct = malloc(sizeof *pointer_to_anonymous_struct);
?
But what is the point in having an anonymous struct then?

Look at it the other way round: in your own example, what would be the
point of using a tag in the structure definition?
Could you supply a real-life example?

Sure:

struct { ... } foo, bar, baz;

foo, bar and baz are all the objects of this type needed by the program
and they are used in a single translation unit. What would a tag buy you?

Dan
 
S

S.Tobias

If you can't grasp the difference between a pointer and the pointed-to
object, stop messing with the C standard and read K&R2 (again).

Why being so aggressive at me? My seemingly naive question was not
asked without a reason, which I explained at length in my answer
to Barry Schwarz' post (I assume that hadn't reached you before
you sent yours). I think my remark in parentheses (which you didn't
quote) more than suggests I do understand the difference between
pointer type and pointed to type (I explicitly wrote that I did consider
pointer type alignment possibility, but rejected it).

I don't understand how you can judge other people's understanding
only after one posting. Please, explain yourself.
 
C

Chris Torek

The last manner is also found in: 6.3.2.3#7 (Pointers) and 7.20.3#1
(Memory management functions). See for yourself: in both cases "pointer
alignment" refers to the pointer *value*, not pointer type.[/QUOTE]

I am not going to address most of this (due to lack of time), but
I want to make several points here.

First, the value of a pointer to some type "T" -- i.e., a value of
type "T *" -- indeed possesses this "alignment" characteristic, so
that it is possible to ask whether such a pointer is correctly
aligned. (This question is inherently machine-dependent, however,
and on *some* machines it is meaningless.)

But note that if we store this pointer value in an object:

T *pointer_object;

we then have an *object*, not a variable. This object can have an
address:

T **p2 = &pointer_object;

(here the object's address is stored in yet another object, "p2",
of type "T **). If "pointer_object" has an address, that value --
a value of type "T **" -- *also* possesses this "alignment"
characteristic. Thus, we can ask not only whether the value stored
in "pointer_object" is correctly aligned, but also whether
"pointer_object" itself is correctly aligned. Having stored
&pointer_object in p2, we can then ask whether "the object p2" is
correctly aligned, via this question:

"does &p2 satisfy its machine-dependent alignment constraints?"

and if we store &p2 in yet another object:

T ***p3 = &p2;

we can then go on to ask whether "the object p3" (or more precisely,
the value produced by &p3) is correctly aligned, and so on.

There are thus four possible machine-dependent alignment constraints
arising so far:

(1) the value stored in pointer_object (of type "T *")
(2) the value produced by &pointer_object (type "T **")
(3) the value produced by &p2 (type "T ***")
(3) the value produced by &p3 (type "T ****")

and it makes some sense to ask whether all of them are satisified,
and to ask whether any or all four of these machine-dependent
alignment constraints are identical. Some of the answers are of
course machine-dependent. Since the objects named "pointer_object",
"p2", and "p3" are allocated by the compiler, they had better be
correctly aligned -- the C programmer is not the one responsible
for this -- but the rest of the answers require looking at the
machine.

For a number of existing, even common, machines today, the alignment
constraints for "T *" and "T **" often differ, depending on T.
For instance, "char *" always, by definition, needs only 1-byte
alignment ("C byte", not necessarily 8-bit-octet, although the
machines I am thinking of happen to have 8-bit C bytes too); but
"char **" often requires 4 or 8 byte alignment (32-bit or 64-bit
SPARC and MIPS, for instance).

Now, given the original example, or something at least close to
it:

struct C { char c; };
struct D { double d; };

you will find that, e.g., SPARC systems have sizeof(struct C) == 1
and align "struct C" objects on byte boundaries, while sizeof(struct D)
== 8 and "struct D" objects are always found on 8-byte boundaries.
Nonetheless, on those machines in 32-bit mode (or always for V8 and
earlier SPARC systems), "struct C *" and "struct D *" objects
are always aligned on 4-byte boundaries. In other words, given:

struct C *p1, **p2;
... set p1 and p2 ...

we can test the "alignment validity" (on that SPARC machine, in a
machine-dependent manner) with:

int is_p1_aligned(void) {
/* p1 is always properly aligned */
return 1;
}

int is_p2_aligned(void) {
/* p2 is properly aligned if and only if its low 2 bits are 0 */
return ((int)p2 & 3) == 0;
}

If we add "struct D *p3", however, the "is_p3_aligned" test becomes:

int is_p3_aligned(void) {
/* p3 is properly aligned if and only if its low 3 bits are 0 */
return ((int)p3 & 7) == 0;
}

Thus, the "aligned-ness" of a pointer depends on its type as well as
its value; and for two "struct T1 *" and "struct T2 *" values, the
"aligned-ness" of those two value may require different tests.
 

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

Members online

Forum statistics

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

Latest Threads

Top