[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Alignment of foo[1][1][1][1]

Shao Miller

6/30/2011 4:12:00 AM

Suppose I have type 'foo' and:

sizeof (foo) == 16
alignof (foo) == 2

Suppose I have type 'foo[1][1][1][1]' and:

sizeof (foo[1][1][1][1]) == 16

Can:

alignof (foo[1][1][1][1]) == 4

? I'd like to think not, but is it prohibited? If I do:

typedef foo bar[1][1][1][1];
bar * my_bar = malloc(sizeof *bar);
foo * my_foo = (foo *) my_bar;

certainly 'my_bar' points to an object whose alignment satisfies type
'foo'. But what about the other way around?

typedef foo bar[1][1][1][1];
foo * my_foo = malloc(sizeof *foo);
bar * my_bar = (bar *) my_foo;

'my_foo' could point to an object aligned for '2', but if the alignment
requirement for 'bar' is '4', then the behaviour is undefined.

With a size of '16', array elements would always satisfy both alignment
requirements.

My guess is that no implementation does this, but again: How about
Standard-wise?
41 Answers

Shao Miller

6/30/2011 4:13:00 AM

0

On 6/29/2011 11:11 PM, Shao Miller wrote:
> Suppose I have type 'foo' and:
>
> sizeof (foo) == 16
> alignof (foo) == 2
>
> Suppose I have type 'foo[1][1][1][1]' and:
>
> sizeof (foo[1][1][1][1]) == 16
>
> Can:
>
> alignof (foo[1][1][1][1]) == 4
>
> ? I'd like to think not, but is it prohibited? If I do:
>
> typedef foo bar[1][1][1][1];
> bar * my_bar = malloc(sizeof *bar);
> foo * my_foo = (foo *) my_bar;
>
> certainly 'my_bar' points to an object whose alignment satisfies type
> 'foo'. But what about the other way around?
>
> typedef foo bar[1][1][1][1];
> foo * my_foo = malloc(sizeof *foo);
> bar * my_bar = (bar *) my_foo;
>
> 'my_foo' could point to an object aligned for '2', but if the alignment
> requirement for 'bar' is '4', then the behaviour is undefined.
>
> With a size of '16', array elements would always satisfy both alignment
> requirements.
>
> My guess is that no implementation does this, but again: How about
> Standard-wise?

Erm, pretend I didn't use 'malloc', there. That's besides the point.

Harald van D?k

7/1/2011 4:57:00 PM

0

On Jun 30, 5:11 am, Shao Miller <sha0.mil...@gmail.com> wrote:
> My guess is that no implementation does this,

Perhaps not for arrays of length 1, but it could be a sensible
decision to require the same alignment as an int for
char[sizeof(int)]. And on my system, the natural alignment for long
long is 8 bytes, but the compiler aligns them to 4 bytes mainly to
avoid changing the ABI. It could be a sensible future decision to keep
that alignment for long long, but align arrays of long long to 8
bytes, if the cost of the ABI change would be acceptably small for
arrays. (Not that I think that is going to happen, but still...)

> but again: How about
> Standard-wise?

I don't think the standard says anything about it, which in this case
means implementors are given the freedom to use whatever alignment
works best for them.

lawrence.jones

7/2/2011 6:56:00 PM

0

Shao Miller <sha0.miller@gmail.com> wrote:
> Suppose I have type 'foo' and:
>
> sizeof (foo) == 16
> alignof (foo) == 2
>
> Suppose I have type 'foo[1][1][1][1]' and:
>
> sizeof (foo[1][1][1][1]) == 16
>
> Can:
>
> alignof (foo[1][1][1][1]) == 4
>
> ? I'd like to think not, but is it prohibited?

I'm afraid it's hard to say. The problem is that there are at least two
potentially different kinds of alignment requirements, which I'll call
the *necessary* alignment and the *preferred* alignment. The necessary
alignment is the alignment required by the underlying hardware and the
implementation's code generation in order for things to work correctly.
The preferred alignment may be stricter and is what the implementation
actually uses, typically for performance reasons. For example, on a
typical linearly addressed machine that allows unaligned accesses, the
necessary alignment for all types is 1, but implementations almost
always use an alignment equal to the size for the fundamental data
types.

The C Standard requires that any object be usable as if it were an array
with a single element. Thus, the necessary alignment of an array cannot
be stricter than the necessary alignment of its element type. However,
there certainly are implementations that align arrays more strictly than
their element type for performance reasons, and I wouldn't be surprised
to find some that do the same for structure types (although I've never
encountered one).

The Standard says that _Alignof() returns the "required" alignment, but
it's not clear exactly what "required" means in this context. Is it the
necessary alignment, the preferred alignment, or maybe even something in
between?
--
Larry Jones

The authorities are trying to silence any view contrary to their own!
-- Calvin

Harald van D?k

7/2/2011 9:17:00 PM

0

On Jul 2, 7:56 pm, lawrence.jo...@siemens.com wrote:
> The C Standard requires that any object be usable as if it were an array
> with a single element.  Thus, the necessary alignment of an array cannot
> be stricter than the necessary alignment of its element type.

In n1256, the only relevant wording regarding treating arbitrary
objects as arrays that I can find is this:

"For the purposes of these operators, a pointer to an object that is
not an element of an
array behaves the same as a pointer to the first element of an array
of length one with the
type of the object as its element type." (for the + - < <= > >= ==
and != operators)

which does not suggest to me that objects behave as arrays of length 1
in other aspects. Am I overlooking something?

Tim Rentsch

7/3/2011 10:23:00 PM

0

Shao Miller <sha0.miller@gmail.com> writes:

> Suppose I have type 'foo' and:
>
> sizeof (foo) == 16
> alignof (foo) == 2
>
> Suppose I have type 'foo[1][1][1][1]' and:
>
> sizeof (foo[1][1][1][1]) == 16
>
> Can:
>
> alignof (foo[1][1][1][1]) == 4
>
> ? I'd like to think not, but is it prohibited? [snip]

No, it's conforming. An array must be aligned at least as
strictly as its elements, but the converse doesn't hold,
even for arrays of length 1. The alignments for types (foo)
and (foo[1]) don't have to be the same, even though in any
sane implementation they will be.

Tim Rentsch

7/3/2011 10:57:00 PM

0

lawrence.jones@siemens.com writes:

> Shao Miller <sha0.miller@gmail.com> wrote:
>> Suppose I have type 'foo' and:
>>
>> sizeof (foo) == 16
>> alignof (foo) == 2
>>
>> Suppose I have type 'foo[1][1][1][1]' and:
>>
>> sizeof (foo[1][1][1][1]) == 16
>>
>> Can:
>>
>> alignof (foo[1][1][1][1]) == 4
>>
>> ? I'd like to think not, but is it prohibited?
>
> I'm afraid it's hard to say. The problem is that there are at least two
> potentially different kinds of alignment requirements, which I'll call
> the *necessary* alignment and the *preferred* alignment. The necessary
> alignment is the alignment required by the underlying hardware and the
> implementation's code generation in order for things to work correctly.
> The preferred alignment may be stricter and is what the implementation
> actually uses, typically for performance reasons. For example, on a
> typical linearly addressed machine that allows unaligned accesses, the
> necessary alignment for all types is 1, but implementations almost
> always use an alignment equal to the size for the fundamental data
> types.
>
> The C Standard requires that any object be usable as if it were an array
> with a single element. Thus, the necessary alignment of an array cannot
> be stricter than the necessary alignment of its element type.

You mean this the other way around - the alignment of an array
type must be at least as strict as the element type, and may
in fact be more strict. The requirement you mention is in
reference to element and array objects, not types; it doesn't
bear on the issue of alignment of array types, because the
pointers involved always point to an element of the array in
question, ie, they are of element type, not array type [*].

[*] With the understanding that the element type may itself be
a (different) array type, but that doesn't change the point.


> However,
> there certainly are implementations that align arrays more strictly than
> their element type for performance reasons, and I wouldn't be surprised
> to find some that do the same for structure types (although I've never
> encountered one).
>
> The Standard says that _Alignof() returns the "required" alignment, but
> it's not clear exactly what "required" means in this context. Is it the
> necessary alignment, the preferred alignment, or maybe even something in
> between?

Surely the meaning of _Alignof() is meant to coincide with what
is necessary for conversion of a pointer to the type in question.
So for example,

char *stuff = malloc( _Alignof (T) + sizeof (T) );
... verify the malloc succeeded ...

T *displaced = (T*) (stuff + _Alignof (T));

must work on a conforming implementation. It's also possible
some lesser values would work, but _Alignof (T) must be
/guaranteed/ to work, since otherwise having _Alignof would be of
no value.

(I think it goes without saying that _Alignof also must be such
that the alignments of members if T is a struct or union type, or
elements if T is an array type, will each have their individual
requirements satisfied -- meaning they can be accessed normally
and their addresses will work when converted to their respective
types. The alignment of a struct type must take into account the
alignments of its members, etc.)

lawrence.jones

7/6/2011 4:06:00 AM

0

Tim Rentsch <txr@alumni.caltech.edu> wrote:
> lawrence.jones@siemens.com writes:
> > The C Standard requires that any object be usable as if it were an array
> > with a single element. Thus, the necessary alignment of an array cannot
> > be stricter than the necessary alignment of its element type.
>
> You mean this the other way around - the alignment of an array
> type must be at least as strict as the element type, and may
> in fact be more strict.

No, I meant exactly what I said. You're either missing the distinction
I was trying to draw between the necessary and preferred alignments or
you're conflating them.

> The requirement you mention is in
> reference to element and array objects, not types; it doesn't
> bear on the issue of alignment of array types, because the
> pointers involved always point to an element of the array in
> question, ie, they are of element type, not array type [*].

But a pointer to an array must compare equal to a pointer to the first
element (when converted to a common type, of course), which isn't
possible in general unless the necessary alignments are the same. The
preferred alighments can differ as you said above.
--
Larry Jones

These findings suggest a logical course of action. -- Calvin

Shao Miller

7/6/2011 2:07:00 PM

0

On 7/2/2011 17:16, Harald van Dijk wrote:
> On Jul 2, 7:56 pm, lawrence.jo...@siemens.com wrote:
>> The C Standard requires that any object be usable as if it were an array
>> with a single element. Thus, the necessary alignment of an array cannot
>> be stricter than the necessary alignment of its element type.
>
> In n1256, the only relevant wording regarding treating arbitrary
> objects as arrays that I can find is this:
>
> "For the purposes of these operators, a pointer to an object that is
> not an element of an
> array behaves the same as a pointer to the first element of an array
> of length one with the
> type of the object as its element type." (for the + -< <=> >= ==
> and != operators)
>
> which does not suggest to me that objects behave as arrays of length 1
> in other aspects. Am I overlooking something?

Do you mean such as the cast concern of the original post? That seems
like a slippery slope. :S

Harald van D?k

7/6/2011 3:56:00 PM

0

On Jul 6, 3:07 pm, Shao Miller <sha0.mil...@gmail.com> wrote:
> On 7/2/2011 17:16, Harald van D?k wrote:
> > On Jul 2, 7:56 pm, lawrence.jo...@siemens.com wrote:
> >> The C Standard requires that any object be usable as if it were an array
> >> with a single element.  Thus, the necessary alignment of an array cannot
> >> be stricter than the necessary alignment of its element type.
>
> > In n1256, the only relevant wording regarding treating arbitrary
> > objects as arrays that I can find is this:
>
> > "For the purposes of these operators, a pointer to an object that is
> > not an element of an
> >   array behaves the same as a pointer to the first element of an array
> > of length one with the
> >   type of the object as its element type." (for the + -<  <=>  >= ==
> > and != operators)
>
> > which does not suggest to me that objects behave as arrays of length 1
> > in other aspects. Am I overlooking something?
>
> Do you mean such as the cast concern of the original post?  That seems
> like a slippery slope. :S

In what way? I don't see any downsides to disallowing

int i = 0;
++(*(int(*)[1])&i)[0];

If you need an array, do this:

int i[1] = { 0 };
++i[0];

If you don't need an array, do this:

int i = 0;
++i;

Do you have a real example where it would be useful for you to
reinterpret a non-array as an array (beyond what the standard already
permits)?

Shao Miller

7/6/2011 5:25:00 PM

0

On 7/6/2011 00:06, lawrence.jones@siemens.com wrote:
> Tim Rentsch<txr@alumni.caltech.edu> wrote:
>> lawrence.jones@siemens.com writes:
>>> The C Standard requires that any object be usable as if it were an array
>>> with a single element. Thus, the necessary alignment of an array cannot
>>> be stricter than the necessary alignment of its element type.
>>
>> You mean this the other way around - the alignment of an array
>> type must be at least as strict as the element type, and may
>> in fact be more strict.
>
> No, I meant exactly what I said. You're either missing the distinction
> I was trying to draw between the necessary and preferred alignments or
> you're conflating them.
>
>> The requirement you mention is in
>> reference to element and array objects, not types; it doesn't
>> bear on the issue of alignment of array types, because the
>> pointers involved always point to an element of the array in
>> question, ie, they are of element type, not array type [*].
>
> But a pointer to an array must compare equal to a pointer to the first
> element (when converted to a common type, of course), which isn't
> possible in general unless the necessary alignments are the same. The
> preferred alighments can differ as you said above.

If I understand you correctly, "necessary alignment" is that which is
involved in the "correctly aligned" bit of pointer conversions and
"preferred alignment" would be where an implementation causes

int ia[100];

to happen to land.

Regardless of which of these '_Alignof' uses, if we have:

/* ...foo established... */
typedef foo a_1_1_foo[1][1];

char * cp = malloc(sizeof (a_1_1_foo) * 10);
/* Assume success */
cp += _Alignof (foo);

'cp' now theoretically points to an object which could have type 'foo'.
But how can we say whether it points to a 'foo', a 'foo[1]', a
'foo[1][1]', a 'foo[1][1][1]', etc.? The "points to an object that is
not an element of an array" doesn't really seem determinable.

/* Correctly aligned conversion? */
a_1_1_foo * test = (void *) cp;

Or is that "jumping too far?"

foo * step1 = (void *) cp;

Yes, 'step1' is correctly aligned.

foo (* step2)[1] = (void *) step1;

Yes, 'step1' didn't point to an element, so it is treated as though it
pointed to the sole element of an array. This urges that 'foo[1]' has
the same alignment requirement as 'foo'.

a_1_1_foo * step3 = (void *) step2;

Hmm... 'step2' doesn't point to an element of an array according to its
type, but it "came from" a pointer which points to an element of an
array object (perhaps)... It strikes me as being similar to a
containing 'struct' (or 'union') with a single member, where the
alignment requirement of the 'struct' is stricter than the member.