Padding involved

S

Stephen Sprunk

Would it be too much trouble to ask to see the exact source
you actually compiled and run? The source as posted has at least
two problems: The twodouble/twdouble mismatch,

Change made in source and recompiled/executed:

% cat foo.c
#include <stdio.h>
#define alignof(t) __alignof__(t)
struct twodouble { double x; double y; };
int main(void) {
printf("alignof(double) = %zu\n", alignof(double));
printf("alignof(double[2]) = %zu\n", alignof(double[2]));
printf("alignof(double complex) = %zu\n", alignof(double _Complex));
printf("alignof(struct twodouble) = %zu\n", alignof(struct twodouble));
}
% gcc -std=c99 -pedantic -W -Wall foo.c
% ./a.out
alignof(double) = 8
alignof(double[2]) = 8
alignof(double complex) = 8
alignof(struct twodouble) = 4
and the use of __alignof__ (compiler-specific magic? another typo? or
what?).

My GCC doesn't support _Alignof(), but __alignof__ should be the same.

It's possible that, for a related reason, GCC doesn't provide the
expected alignment for struct twodouble. Unfortunately, I can't upgrade
it right now to see if the result has changed in more recent versions.

S
 
K

Keith Thompson

Stephen Sprunk said:
Would it be too much trouble to ask to see the exact source
you actually compiled and run? The source as posted has at least
two problems: The twodouble/twdouble mismatch,

Change made in source and recompiled/executed:

% cat foo.c
#include <stdio.h>
#define alignof(t) __alignof__(t)
struct twodouble { double x; double y; };
int main(void) {
printf("alignof(double) = %zu\n", alignof(double));
printf("alignof(double[2]) = %zu\n", alignof(double[2]));
printf("alignof(double complex) = %zu\n", alignof(double _Complex));
printf("alignof(struct twodouble) = %zu\n", alignof(struct twodouble));
}
% gcc -std=c99 -pedantic -W -Wall foo.c
% ./a.out
alignof(double) = 8
alignof(double[2]) = 8
alignof(double complex) = 8
alignof(struct twodouble) = 4
and the use of __alignof__ (compiler-specific magic? another typo? or
what?).

My GCC doesn't support _Alignof(), but __alignof__ should be the same.

It's possible that, for a related reason, GCC doesn't provide the
expected alignment for struct twodouble. Unfortunately, I can't upgrade
it right now to see if the result has changed in more recent versions.

Interesting. I get the same output on my 32-bit system after replacing
__alignof__ by _Alignof and compiling with -std=c11.

It doesn't seem to me to make sense for struct twodouble to have a
weaker alignment requirement than double, but I'm not sure it violates
the standard. I don't see a specific statement that the alignment of a
struct must be at least the alignment of any of its members, and as long
as the generated code works (this is on an x86, which permits arbitrary
alignments with some performance penalty), it's likely conforming.
 
K

Keith Thompson

Keith Thompson said:
Stephen Sprunk said:
On 3/30/2014 7:53 PM, Stephen Sprunk wrote:
They matched in what I compiled/ran; I changed the struct's name before
posting for clarity but made a typo.

Would it be too much trouble to ask to see the exact source
you actually compiled and run? The source as posted has at least
two problems: The twodouble/twdouble mismatch,

Change made in source and recompiled/executed:

% cat foo.c
#include <stdio.h>
#define alignof(t) __alignof__(t)
struct twodouble { double x; double y; };
int main(void) {
printf("alignof(double) = %zu\n", alignof(double));
printf("alignof(double[2]) = %zu\n", alignof(double[2]));
printf("alignof(double complex) = %zu\n", alignof(double _Complex));
printf("alignof(struct twodouble) = %zu\n", alignof(struct twodouble));
}
% gcc -std=c99 -pedantic -W -Wall foo.c
% ./a.out
alignof(double) = 8
alignof(double[2]) = 8
alignof(double complex) = 8
alignof(struct twodouble) = 4
and the use of __alignof__ (compiler-specific magic? another typo? or
what?).

My GCC doesn't support _Alignof(), but __alignof__ should be the same.

It's possible that, for a related reason, GCC doesn't provide the
expected alignment for struct twodouble. Unfortunately, I can't upgrade
it right now to see if the result has changed in more recent versions.

Interesting. I get the same output on my 32-bit system after replacing
__alignof__ by _Alignof and compiling with -std=c11.

It doesn't seem to me to make sense for struct twodouble to have a
weaker alignment requirement than double, but I'm not sure it violates
the standard. I don't see a specific statement that the alignment of a
struct must be at least the alignment of any of its members, and as long
as the generated code works (this is on an x86, which permits arbitrary
alignments with some performance penalty), it's likely conforming.

Even stranger, gcc's value for _Offsetof seems to be inconsistent with
the alignment it actually uses:

#include <stdio.h>
#include <stddef.h>

#define ALIGNOF(type) (offsetof(struct { char c; type t; }, t))

struct twodouble { double x; double y; };

int main(void) {
printf("_Alignof(double) = %zu\n", _Alignof(double));
printf("ALIGNOF(double) = %zu\n", ALIGNOF(double));
printf("_Alignof(struct twodouble) = %zu\n", _Alignof(struct twodouble));
printf("ALIGNOF(struct twodouble) = %zu\n", ALIGNOF(struct
twodouble));
}

The output (on a 32-bit x86 system with gcc 4.7.0):

_Alignof(double) = 8
ALIGNOF(double) = 4
_Alignof(struct twodouble) = 4
ALIGNOF(struct twodouble) = 4

So gcc claims (via the result of the _Offsetof operator) that double has
an 8-byte alignment, but it only imposes a 4-byte alignment when it's
a struct member. That looks like a bug to me.
 
K

Kaz Kylheku

The output (on a 32-bit x86 system with gcc 4.7.0):

_Alignof(double) = 8
ALIGNOF(double) = 4
_Alignof(struct twodouble) = 4
ALIGNOF(struct twodouble) = 4

So gcc claims (via the result of the _Offsetof operator) that double has
an 8-byte alignment, but it only imposes a 4-byte alignment when it's
a struct member. That looks like a bug to me.

Bug #52023:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023

Reported by Paul Eggert in January 2012.

"On x86, alignof (double) should be 4, since that's the alignment
requirement used for 'double' when laying out structures. But with
GCC alignof incorrectly returns 8."

Fixed for gcc 4.9, in December 2013.
 
S

Stephen Sprunk

Bug #52023:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023

Reported by Paul Eggert in January 2012.

"On x86, alignof (double) should be 4, since that's the alignment
requirement used for 'double' when laying out structures. But with
GCC alignof incorrectly returns 8."

Fixed for gcc 4.9, in December 2013.

Very interesting; thanks.

Does(Did) GCC actually use 4- or 8-byte alignment for doubles when _not_
a member of a structure? For arrays of double?

S
 
S

Stephen Sprunk

It's not even permitted. As Keith cited, according to N1570 6.5.3.4p3,
_Alignof(double[2]) == _Alignof(double).

I've acknowledged that I missed that clause. The restriction it imposes
is new in C2011, even thought it could have been expressed in different
terms in previous versions of the standard.

AIUI, such additions appear because that was the intent (or at least
known practice) all along but someone discovered it wasn't actually
stated and asked for clarification.
There's nothing stopping the implementation from _delivering_ stricter
alignment than promised in order to make use of such instructions, but
there doesn't seem to be any way for it to promise to do so.

Alignment requirements are implementation-defined, which means that a
conforming implementation of C must come with documentation that
describes them. Prior to C2011, that documentation could have specified
that double[N] will have 16 byte alignment whenever N is even. Keith
postulates to the contrary, but I don't think it can easily be proven.

I wouldn't expect array dimension to affect alignment, and IMHO most
people would assume an object would have the same alignment as an array
of one object (and vice versa). It seems worth saying so explicitly,
though, based on the debate here.
There is no text that says so directly. It's something that can be
derived from what the standard says about arrays, the offsetof() macro
(which implies that the offset is a constant depending only upon the
struct definition, rather than being dependent upon which instance of
the struct is being referred to), and alignment requirements.

That seems sufficient, but wouldn't it be simpler for them to just say
so explicitly if that was the intent?

S
 
J

James Kuyper

That seems sufficient, but wouldn't it be simpler for them to just say
so explicitly if that was the intent?

Yes, and I wouldn't object to adding such text, at least as a footnote.

However, realize that there's a wide variety of other interesting
mathematical results that can be derived from those same facts. For
instance, in C2011, the requirement was added that alignment
requirements had to be powers of 2, which matches what essentially all
known implementations of C actually do, or have ever actually done.
However, prior to that change, a conforming implementation could have
had alignment requirements for short and long that were 3 bytes and 5
bytes, respectively. From C99, it could be proven, using the same set of
facts mentioned above, that any struct or union containing both a short
and a long must have a alignment requirement when using that
implementation, which is an integer multiple of both 3 and 5, and
therefore must be a multiple of 15.

Should the C99 standard have explicitly said something that would lead
to that conclusion more directly, perhaps by expressing the relationship
in terms of LCM (least common multiple)? I know from personal experience
that very few people were aware of that fact. More than a few people
argued with me about this when I brought it up. I think this was mainly
because most of them had the "power of 2" rule already engraved in their
brains, long before it was officially adopted as a requirement. When a
and b are non-negative integer powers of two, LCM(a,b) == MAX(a,b),
which is what most people actually used when thinking about such issues.

How do you decide which technically redundant facts need to be
explicitly spelled out, and which ones should be left for readers to
derive for themselves?
 
P

Phil Carmody

Stephen Sprunk said:
Very interesting; thanks.

Does(Did) GCC actually use 4- or 8-byte alignment for doubles when _not_
a member of a structure? For arrays of double?

If gcc has gone all anti-FPU, and pro VFP, then I'm surprised that the
alignment isn't 8 bytes, as at least in several generations of the
vector instructions non-aligned loads and stores instructions were a
performance hit. Optimising for packing in structs, but for speed
elsewhere does seem to make a little bit of sense in a twisted-x86
kinda way. However, aligning anything at a finer granularity than
the _Alignof is just plain wrong. (So this is now a bug no matter
what Richard Henderson says on that bugzilla.)

Do the VFP-related switches change the behaviour?

Seems like Keith's at least in part actively on the case:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54188

Phil
 
P

Phil Carmody

James Kuyper said:
Yes, and I wouldn't object to adding such text, at least as a footnote.

However, realize that there's a wide variety of other interesting
mathematical results that can be derived from those same facts. For
instance, in C2011, the requirement was added that alignment
requirements had to be powers of 2, which matches what essentially all
known implementations of C actually do, or have ever actually done.

Don't say that - there are probably corners of N-bit la-la-land
(for N itself not a power of 2) for which it hasn't always held!
I can't remember what some old 24-bit DSPs did when they were
compiled to pack strings (3 chars per word), as the whole concept
of doing dodgy stuff that required knowledge of alignment was so
taboo that nobody ever seemed to do it. You were either dealing
with words, or you were dealing with packed strings, there was
never a sane context where you'd need to deal with either.
How do you decide which technically redundant facts need to be
explicitly spelled out, and which ones should be left for readers to
derive for themselves?

I'd say this can be derived from basic principles, as it
seems rather obvious (including the LCM aspect you mention,
but my background is pure mathematics).

Phil
 
S

Stephen Sprunk

If gcc has gone all anti-FPU, and pro VFP, then I'm surprised that the
alignment isn't 8 bytes, as at least in several generations of the
vector instructions non-aligned loads and stores instructions were a
performance hit. Optimising for packing in structs, but for speed
elsewhere does seem to make a little bit of sense in a twisted-x86
kinda way. However, aligning anything at a finer granularity than
the _Alignof is just plain wrong. (So this is now a bug no matter
what Richard Henderson says on that bugzilla.)

Do the VFP-related switches change the behaviour?

Not that I know of.

FWIW, GCC can auto-vectorize array accesses regardless of the array's
alignment; it uses non-vector ops for any initial unaligned elements,
then switches to vector ops for the main loop, and then switches back to
non-vector ops for any remainder at the end. That's the only portable
way to do it. If you want a guarantee that your entire array is
properly aligned and sized for vector ops, then use GCC's explicit
vector types.

S
 
S

Stephen Sprunk

Yes, and I wouldn't object to adding such text, at least as a
footnote.

However, realize that there's a wide variety of other interesting
mathematical results that can be derived from those same facts. For
instance, in C2011, the requirement was added that alignment
requirements had to be powers of 2, which matches what essentially
all known implementations of C actually do, or have ever actually
done. However, prior to that change, a conforming implementation
could have had alignment requirements for short and long that were 3
bytes and 5 bytes, respectively. From C99, it could be proven, using
the same set of facts mentioned above, that any struct or union
containing both a short and a long must have a alignment requirement
when using that implementation, which is an integer multiple of both
3 and 5, and therefore must be a multiple of 15.

Could one have addressed that by stating the struct's alignment must be
a positive integer multiple of each* member's alignment?

(* Or should that be "every"? Neither sounds exactly correct.)

Once you require power-of-two alignments, though, it suffices to say
that the struct's alignment must be at least as strict as all of its
members.
Should the C99 standard have explicitly said something that would
lead to that conclusion more directly, perhaps by expressing the
relationship in terms of LCM (least common multiple)? I know from
personal experience that very few people were aware of that fact.
More than a few people argued with me about this when I brought it
up. I think this was mainly because most of them had the "power of 2"
rule already engraved in their brains, long before it was officially
adopted as a requirement. When a and b are non-negative integer
powers of two, LCM(a,b) == MAX(a,b), which is what most people
actually used when thinking about such issues.

Good point, though the argument for LCM would be clearer if your example
alignments weren't relatively prime, i.e. if GCF(a,b) != 1.

Now, of course, LCM(a,b) == MAX(a,b) and GCF(a,b) == MIN(a,b).
How do you decide which technically redundant facts need to be
explicitly spelled out, and which ones should be left for readers to
derive for themselves?

I suppose that's a judgment call, but I found it surprising that when
searching N1570 for "alignment" and then "struct", I found absolutely
nothing useful about how structs needed to be aligned. That seems to
indicate they erred on the side of not enough redundancy, but I can
appreciate that redundancy introduces a risk of inconsistency.

S
 
J

James Kuyper

On 31-Mar-14 16:53, James Kuyper wrote: ....

Could one have addressed that by stating the struct's alignment must be
a positive integer multiple of each* member's alignment?

(* Or should that be "every"? Neither sounds exactly correct.)

I think "every" would be correct.
Once you require power-of-two alignments, though, it suffices to say
that the struct's alignment must be at least as strict as all of its
members.

Which is why I had to hark back to an earlier version of the standard to
come up with an example of something that is less obvious.
Good point, though the argument for LCM would be clearer if your example
alignments weren't relatively prime, i.e. if GCF(a,b) != 1.

I suppose it would be clearer what the general rule is if a and b have
some factors in common, and each one has some factors not in common with
the other; such as 4 and 6, with an LCM of 12.
Now, of course, LCM(a,b) == MAX(a,b) and GCF(a,b) == MIN(a,b).


I suppose that's a judgment call, but I found it surprising that when
searching N1570 for "alignment" and then "struct", I found absolutely
nothing useful about how structs needed to be aligned. That seems to
indicate they erred on the side of not enough redundancy, but I can
appreciate that redundancy introduces a risk of inconsistency.

In standardese, that's handled by distinguishing between normative and
non-normative text. The normative text should never say the same thing
two different ways, because of the potential problems if the two ways
turn out to be subtly in conflict with each other. However, you can put
redundant statements in non-normative text, such as footnotes, and if
they turn out to conflict with the normative text, the normative text is
right, and the non-normative text is not. The accuracy of the standard
itself isn't in danger, just that of the individual footnotes.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
On 03/29/2014 03:57 AM, Keith Thompson wrote:
...
Actually, that's precisely what double[2] is; and
_Alignof(double[2]) probably would be 16 on such a platform.

N1570 6.5.3.4p3:

The _Alignof operator yields the alignment requirement of its
operand type. The operand is not evaluated and the result is
an integer constant. When applied to an array type, the result
is the alignment requirement of the element type.

Ah - that's new, I think - I haven't had time to fully digest the
changes made in C2011. In principle the same requirement could have
been worded in earlier versions of the standard in terms of the
alignment of the type without mentioning _Alignof(), but I don't
think that it was. Am I correct?

Search for every occurrence of "alignment" in N1256, I see no
explicit statement about the alignment of array types (which is a
bit surprising).

But I think the *required* alignment for an array type was already
the same as the required alignment for the element type.

For example, I *think* this program, which treats "slices" of a
double[3] array as double[2] arrays, is strictly conforming in
both C99 and C11. If double[2] could have a stricter alignment
requirement than double, its behavior would be undefined under any
implementation that imposes such an alignment.

#include <stdio.h>

typedef double pair[2];

static void print(pair *p) {
printf("%g %g\n", (*p)[0], (*p)[1]);
}

int main(void) {
double arr[3] = { 10.0, 20.0, 30.0 };
pair *p0 = (pair*)&arr[0];
pair *p1 = (pair*)&arr[1];
print(p0);
print(p1);
}

If you mean the example program as part of an argument, it's
a circular argument. The program is strictly conforming if
and only if the alignment of double[2] must be the same as
the alignment of double. Saying the given program is strictly
conforming is just a sneaky way of begging the question.

It wasn't *quite* meant as an argument, more as a way to restate
the question in a perhaps clearer manner.

I see. How the comment is phrased makes it sound more like it's
meant to be an argument than a restatement. So you might want
to make that distinction more clear. But let's move on.
I *think* that C99 permits the kinds of access in this program
(and I'd be very surprised to see an implementation where it
doesn't work) but I haven't found wording that proves or disproves
it.

In the absence of any requirement that constrains an alignment
further, an implementation is free to choose the alignment of an
array type to be whatever it wants, subject to certain base
conditions (specifically the alignment of the element type must
evenly divide the alignment of the array type, and the alignment
of the array type must evenly divided the size of the type as a
whole, ie, a single instance of that array type). So, unless
there is such a requirement, the example program may be subject
to undefined behavior (because the rule for converting pointer
types mentions undefined behavior explicitly when there are
alignment problems). I think it's easy to see that there is no
such requirement in C99 -- simply check each occurrence of
"alignment" in the text, plus a review of the rules for pointer
conversion in section 6.3.2.3. Is there something you can point
to that changes that? If you can't, then I think it's reasonable
to say the point is settled and the above example program is not
strictly conforming under a strict technical reading of the
Standard.

By the way, I agree with your (implied?) point that the example
program is likely to work as expected on all currently existing
implementations, that most C developers expect that it would, and
that this result is what most of the Standards' authors would
expect also, at least as an unconscious assumption. But I don't
think that result is guaranteed by a strict c.s.c-type reading
of C99 (or C90 either, but I haven't gone back to verify that).
 
T

Tim Rentsch

James Kuyper said:
On 03/29/2014 02:02 PM, Stephen Sprunk wrote:
...
It's not even permitted. As Keith cited, according to N1570 6.5.3.4p3,
_Alignof(double[2]) == _Alignof(double).

I've acknowledged that I missed that clause. The restriction it
imposes is new in C2011, even thought it could have been expressed
in different terms in previous versions of the standard.
There's nothing stopping the implementation from _delivering_
stricter alignment than promised in order to make use of such
instructions, but there doesn't seem to be any way for it to
promise to do so.

Alignment requirements are implementation-defined, [snip
elaboration]

This isn't exactly right. The alignments of non-bit-field struct
members are implementation-defined, and the results of _Alignof
in C11 are implementation-defined, but the alignments of types
are not, and have never been, implementation-defined. Indeed if
the alignment of types were implementation-defined, there would
be no reason for the Stadard to say that the results of _Alignof
are implementation-defined, which it does in 6.5.3.4 p5.
 
T

Tim Rentsch

Stephen Sprunk said:
[concerning the relationship of alignment of a struct type
and alignment of the types of members of the struct]

Could one have addressed that by stating the struct's alignment
must be a positive integer multiple of each* member's alignment?

(* Or should that be "every"? Neither sounds exactly correct.)

Here "each" is better. The reason is the alignments in the
different cases are not the same but depend on the member.
Compare, for example,

"Every student worked on the class project."

and

"The professor will grade the homeworks of each student."

In the first case we say "every student" because they were all
working as a group. But in the second case it would be wrong to
say "the homeworks of every student" because students do homework
by themselves, not as a group, and are graded individually.
Similarly the alignment of a struct will be a positive integer
multiple of the alignment of each member - not the same alignment,
or the same multiple, but in each case the one will be some
multiple of the other. There isn't a single alignment for every
member, only for each member.
 
G

glen herrmannsfeldt

Here "each" is better. The reason is the alignments in the
different cases are not the same but depend on the member.
Compare, for example,
"Every student worked on the class project."

"The professor will grade the homeworks of each student."
In the first case we say "every student" because they were all
working as a group.

But "every" also implies that no-one was left out, such as being
sick on those days.
But in the second case it would be wrong to
say "the homeworks of every student" because students do homework
by themselves, not as a group, and are graded individually.

In this case, it doesn't imply that the professor graded "every"
student, maybe the TA graded some of them.

But even more, I have known professors that graded mulitple student
projects as a group, such that everyone got the same grade.

In one case I know (CS138) it was intended to force students
to work together cooperatively. As many projects depend on the
contribution of all members, especially programming projects,
it makes some sense.
Similarly the alignment of a struct will be a positive integer
multiple of the alignment of each member - not the same alignment,
or the same multiple, but in each case the one will be some
multiple of the other. There isn't a single alignment for every
member, only for each member.

-- glen
 
K

Keith Thompson

glen herrmannsfeldt said:
But "every" also implies that no-one was left out, such as being
sick on those days.

This is a minor point, and getting off-topic, but ...
Could one have addressed that by stating the struct's alignment
must be a positive integer multiple of each* member's alignment?

(* Or should that be "every"? Neither sounds exactly correct.)

The phrase "every member's alignment" could imply that the members,
as a group, have an alignment that they share. The phrase "each
member's alignment" more clearly implies that each member has its
own individual alignment, and that the struct's alignment is a
positive integer multiple of the first member's alignment *and*
of the second member's alignment *and* ....

It's not a very strong implication either way, and it would take a
perverse reading to interpret "every" in the way I suggested, but
I find "each" clearer and more precise than "every" in this context.
 
T

Tim Rentsch

Stephen Sprunk said:
[concerning the relationship of alignment of a struct type
and alignment of the types of members of the struct]

Could one have addressed that by stating the struct's alignment
must be a positive integer multiple of each* member's alignment?

(* Or should that be "every"? Neither sounds exactly correct.)

I almost forgot - the alignment of a struct is some positive
integer multiple of each non-bit-field member's alignment.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top