How to be sure a structure field is aligned


P

pozzugno

I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN >=sizeof(long)).

Am I allowed to use a cast to long or int, as in the following instructions?
struct MyStruct s;
(long *)s.buffer = -100000L;
(unsigned long *)s.buffer = +100000UL;
(int *)s.buffer = -100;
(unsigned int *)s.buffer = +100U;
long l = *(long *)s.buffer;
unsigned long ul = *(unsigned long)s.buffer;
int i = *(int *)s.buffer;
unsigned int ui = *(unsigned int *)s.buffer;

I think this could work on some platforms, but is not fully portable (mostly on 16- and 32-bits). It would work only if buffer[] field is correctly aligned in the structure, but it's not guaranteed (it may depends from the previous fields in the structure).

I think there are two solutions.
Avoiding to use cast and use memcpy (but I don't like it):
long l = -100000L;
unsigned long ul = 100000UL;
int i = -100;
unsigned int ui = +100;
memcpy(s.buffer, &l, sizeof(l));
memcpy(s.buffer, &ul, sizeof(ul));
memcpy(s.buffer, &i, sizeof(i));
memcpy(s.buffer, &ui, sizeof(ui));
memcpy(&l, s.buffer, sizeof(l));
memcpy(&ul, s.buffer, sizeof(ul));
memcpy(&i, s.buffer, sizeof(i));
memcpy(&ui, s.buffer, sizeof(ui));

Moving the buffer[] field at the top of the structure, so it is aligned forsure and I can use casting.

Another solution could be to define MyStruct as:

struct MyStruct {
<some fields of different types>
struct {
unsigned char buffer[MAX_BUFLEN];
} buf_aligned;
};

Are thre other solutions?

PS: I'm working on an embedded platform, so I don't have dynamic allocationmalloc/free (otherwise buffer could had be defined as a pointer and the memory space could had be allocated dynamically with malloc that surely returns aligned pointers).
 
Ad

Advertisements

I

Ian Collins

I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).

One simple (cast free) solution would be to use an enum.
 
P

pozzugno

Il giorno giovedì 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).

One simple (cast free) solution would be to use an enum.

I'm sorry, could you detail? If I add an enum field in the structure (I imagine to specify the type of variable stored in the buffer), I will continuehaving the alignment problem on buffer.
 
I

Ian Collins

Il giorno giovedì 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).

One simple (cast free) solution would be to use an enum.

I'm sorry, could you detail? If I add an enum field in the structure (I imagine to specify the type of variable stored in the buffer), I will continue having the alignment problem on buffer.

No, the enum ember will be correctly aligned for all of its types.
 
J

James Kuyper

Il giorno gioved� 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
On 04/19/12 07:45 PM, (e-mail address removed) wrote:
I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).

One simple (cast free) solution would be to use an enum.

I'm sorry, could you detail? If I add an enum field in the structure (I imagine to specify the type of variable stored in the buffer), I will continue having the alignment problem on buffer.

No, the enum ember will be correctly aligned for all of its types.

Did you mean "union" rather than "enum"?
 
I

Ian Collins

Il giorno gioved� 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
On 04/19/12 07:45 PM, (e-mail address removed) wrote:
I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).

One simple (cast free) solution would be to use an enum.

I'm sorry, could you detail? If I add an enum field in the structure (I imagine to specify the type of variable stored in the buffer), I will continue having the alignment problem on buffer.

No, the enum ember will be correctly aligned for all of its types.

Did you mean "union" rather than "enum"?

Oops, yes. It's been a long day...
 
Ad

Advertisements

J

James Kuyper

I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int,
unsigned int, long, unsigned long, null-terminated strings (of
course, MAX_BUFLEN >= sizeof(long)).

Am I allowed to use a cast to long or int, as in the following
instructions?
struct MyStruct s;
(long *)s.buffer = -100000L;
(unsigned long *)s.buffer = +100000UL;
(int *)s.buffer = -100;
(unsigned int *)s.buffer = +100U;
long l = *(long *)s.buffer;
unsigned long ul = *(unsigned long)s.buffer;
int i = *(int *)s.buffer;
unsigned int ui = *(unsigned int *)s.buffer;

I think this could work on some platforms, but is not fully portable
(mostly on 16- and 32-bits). It would work only if buffer[] field is
correctly aligned in the structure, but it's not guaranteed (it may
depends from the previous fields in the structure).

I think there are two solutions.
Avoiding to use cast and use memcpy (but I don't like it):
long l = -100000L;
unsigned long ul = 100000UL;
int i = -100;
unsigned int ui = +100;
memcpy(s.buffer, &l, sizeof(l));
memcpy(s.buffer, &ul, sizeof(ul));
memcpy(s.buffer, &i, sizeof(i));
memcpy(s.buffer, &ui, sizeof(ui));
memcpy(&l, s.buffer, sizeof(l));
memcpy(&ul, s.buffer, sizeof(ul));
memcpy(&i, s.buffer, sizeof(i));
memcpy(&ui, s.buffer, sizeof(ui));

That works, but is not the best solution.
Moving the buffer[] field at the top of the structure, so it is
aligned for sure and I can use casting.

The structure will have an alignment requirement at least as great as
the most strictly aligned type of any member. If the other members of
the structure include an 'int', then putting buffer at the beginning is
sufficient to ensure that it's correctly aligned for conversion to
'int'. If the other members include a long, then putting buffer at the
beginning will be sufficient to ensure it's correctly aligned for a
long. Otherwise, there's no guarantee. Even if those cases apply, it's a
bad idea to rely upon something like that: your code using buffer could
break if you remove or change the types of other members of the struct.
Another solution could be to define MyStruct as:

struct MyStruct {
<some fields of different types>
struct {
unsigned char buffer[MAX_BUFLEN];
} buf_aligned;
};

The fact that you think this makes a difference suggests that you
believe structs always have universal alignment. That may be true on
many systems, but there's no such requirement.
Are thre other solutions?

Yes - what you're trying to do is precisely what unions were invented to
handle. You should define a discriminated union structure:

struct MyStruct {
enum {UNKNOWN, INT, UINT, LONG, ULONG} member_type;
union {
int i;
unsigned int ui;
long l;
unsigned long ul;
} member;
};

The fields member.i, member.ui, member.l, and member.ul are all
guaranteed to be correctly aligned, and are all stored in overlapping
memory locations. Therefore, only one member of the union can be in use
at any given time. Set member_type to indicate which one that is -
that's the feature that makes this a "discriminated" union. The names
I've used for the enumeration constants aren't very good; they should be
longer, to avoid conflict with other identifiers, but I hope you get the
idea. If you're using the same constants in many other contexts, you
should move the definition of the enumeration outside the definition of
the struct.
 
P

pozzugno

Il giorno giovedì 19 aprile 2012 13:02:33 UTC+2, James Kuyper ha scritto:
On 04/19/2012 03:45 AM, (e-mail address removed) wrote:
[...]
Moving the buffer[] field at the top of the structure, so it is
aligned for sure and I can use casting.

The structure will have an alignment requirement at least as great as
the most strictly aligned type of any member. If the other members of
the structure include an 'int', then putting buffer at the beginning is
sufficient to ensure that it's correctly aligned for conversion to
'int'. If the other members include a long, then putting buffer at the
beginning will be sufficient to ensure it's correctly aligned for a
long. Otherwise, there's no guarantee.

I thought the beginning of a struct (its first field) was perfectly aligned
for every primitive type (int, long int, float...). The same as pointer
returned from malloc().
Even if those cases apply, it's a
bad idea to rely upon something like that: your code using buffer could
break if you remove or change the types of other members of the struct.
Sure.

Another solution could be to define MyStruct as:

struct MyStruct {
<some fields of different types>
struct {
unsigned char buffer[MAX_BUFLEN];
} buf_aligned;
};

The fact that you think this makes a difference suggests that you
believe structs always have universal alignment. That may be true on
many systems, but there's no such requirement.

Yes, I thought so. I was wrong :-(

Yes - what you're trying to do is precisely what unions were invented to
handle.
[...]

Yes, this is THE SOLUTION! Thank you very much.
 
B

Barry Schwarz

Il giorno giovedì 19 aprile 2012 13:02:33 UTC+2, James Kuyper ha scritto:
On 04/19/2012 03:45 AM, (e-mail address removed) wrote:
[...]
Moving the buffer[] field at the top of the structure, so it is
aligned for sure and I can use casting.

The structure will have an alignment requirement at least as great as
the most strictly aligned type of any member. If the other members of
the structure include an 'int', then putting buffer at the beginning is
sufficient to ensure that it's correctly aligned for conversion to
'int'. If the other members include a long, then putting buffer at the
beginning will be sufficient to ensure it's correctly aligned for a
long. Otherwise, there's no guarantee.

I thought the beginning of a struct (its first field) was perfectly aligned
for every primitive type (int, long int, float...). The same as pointer
returned from malloc().

No, the only guarantee is that there is no padding before the first
member.

The beginning of a struct is aligned so that every member of the
struct is properly aligned. Given
struct x {short y;};
there is no guarantee that any object of this type is properly aligned
for anything other than a short. Adding a member
long z;
either before or after y will insure that such an object is aligned so
that z is properly aligned. This has the side affect of also insuring
that y will also be aligned properly for a long.

As long as the member buffer from your original post is either the
first member or immediately preceded by a member with the most
stringent alignment, then buffer will also meet this alignment.
 
J

Joe Pfeiffer

I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long, null-terminated strings (of course, MAX_BUFLEN >= sizeof(long)).

<snip>

This is what unions were invented for:

struct MyStruct {
<some fields of different types>

union {
int intval;
float fltval;
char str[MAX_BUFLEN];
} buffer;
};

Is there a reason this isn't useable in your application?
 
Ad

Advertisements

J

James Kuyper

On 04/19/2012 01:09 PM, Barry Schwarz wrote:
....
As long as the member buffer from your original post is ...
... immediately preceded by a member with the most
stringent alignment, then buffer will also meet this alignment.

That assumes there is no padding inserted between those two members.
While there is no good reason for a implementation to insert such
padding, there's also nothing in the standard to prohibit it. I would
strongly recommend against writing code that depends upon such
assumptions; particularly since you need to know details of particular
implementations of C to know which data type is the one with the
strictest alignment requirement.
 
S

Stephen Sprunk

No, the only guarantee is that there is no padding before the first
member.

The beginning of a struct is aligned so that every member of the
struct is properly aligned. Given
struct x {short y;};
there is no guarantee that any object of this type is properly aligned
for anything other than a short. Adding a member
long z;
either before or after y will insure that such an object is aligned so
that z is properly aligned. This has the side affect of also insuring
that y will also be aligned properly for a long.

Are you sure about that? The only guarantee I'm aware of is that y (and
therefore x) will be properly aligned for a short and z will be properly
aligned for a long, possibly (but not necessarily) via the insertion of
padding between y and z.
As long as the member buffer from your original post is either the
first member or immediately preceded by a member with the most
stringent alignment, then buffer will also meet this alignment.

That is a hope, not a guarantee. A suitably perverse compiler _could_
insert padding between the preceding member and the buffer, throwing off
the buffer's alignment.

Using a union is the correct solution because the standard _guarantees_
every member will be properly aligned for its respective type.

S
 
J

James Kuyper

On 19-Apr-12 12:09, Barry Schwarz wrote: ....

Are you sure about that? The only guarantee I'm aware of is that y (and
therefore x) will be properly aligned for a short and z will be properly
aligned for a long, possibly (but not necessarily) via the insertion of
padding between y and z.

Given:
struct x { long z; short y;};

A struct x must be correctly aligned for both long and short, which
means that 'z' has that same characteristic. However, y need only be
correctly aligned for short. In the unlikely circumstance that
_Alignof(long) < _Alignof(short), there could be padding between them.
Such padding would be pointless except in the even more unlikely event
that sizeof(long)%_Alignof(short) != 0, in which case it's mandatory.
However, pointless or not, it's not prohibited.
 
S

Stephen Sprunk

Given:
struct x { long z; short y;};

A struct x must be correctly aligned for both long and short, which
means that 'z' has that same characteristic.

Ah, I missed "before or" in the quote above, so my response only
addressed the "after" case.

Still, why must x (and therefore z) be aligned for short in that case?
However, y need only be
correctly aligned for short. In the unlikely circumstance that
_Alignof(long) < _Alignof(short), there could be padding between them.
Such padding would be pointless except in the even more unlikely event
that sizeof(long)%_Alignof(short) != 0, in which case it's mandatory.
However, pointless or not, it's not prohibited.

That was pretty much my point.

What about in the case of "struct x { short y; long z;};"? Why would x
(and therefore y) need to be aligned for long?

Couldn't a perverse implementation put two bytes of padding after z and
require allocating a struct x such that it is 2-byte aligned but _not_
4-byte aligned? That would result in z being 4-byte aligned, which
seems to be all that is required.

If you prefer a visual reference:

0 1 2 3
yyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
pppppppppppppppp

The two bytes of tail padding keep arrays properly aligned:

0 1 2 3
yyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
ppppppppppppppppyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
ppppppppppppppppyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
ppppppppppppppppyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
pppppppppppppppp


S
 
J

James Kuyper

On 19-Apr-12 14:56, James Kuyper wrote: ....

Ah, I missed "before or" in the quote above, so my response only
addressed the "after" case.

Still, why must x (and therefore z) be aligned for short in that case?

If _Alignof(short) is N, the start of a struct x object must always be
offsetof(struct x, y) bytes before a position which is a multiple of N.
since offsetof() is a constant independent of the actual location of
struct x, consecutive positions for a struct x must therefore be spaced
some integer multiple of N bytes apart. This means that _Alignof(struct
x) must also be an integer multiple of N.
That was pretty much my point.

What about in the case of "struct x { short y; long z;};"? Why would x
(and therefore y) need to be aligned for long?

Just use the same argument as given above, with short replaced by long,
and y replaced by z.
Couldn't a perverse implementation put two bytes of padding after z and
require allocating a struct x such that it is 2-byte aligned but _not_
4-byte aligned? That would result in z being 4-byte aligned, which
seems to be all that is required.

The C standard defines "alignment" as a "requirement that objects of a
particular type be located on storage boundaries with addresses that are
particular multiples of a byte address" (3.2p1). It also says "An
alignment is an implementation-defined integer value representing the
number of bytes between successive addresses at which a given object can
be allocated." (6.2.8p4),

Assume that struct x could be allocated in the way that you describe. It
could not be allocated on any address which is a multiple of 4; it can
only be allocated at positions which are odd multiples of 2. Therefore
_Alignof(struct x) can't be 4 - that would be inconsistent with 3.2p1.
Yet, the positions at which it can be placed are spaced 4 bytes apart,
so according to 6.2.8p4, _Alignof(struct x) must be 4. That assumption
leads to a contradiction, implying that the assumption must be false:
implementations are not allowed to allocate struct x objects in that
fashion.

_Alignof and the words I quoted above from 6.2.8p4 are both new in
C2011. What the committee meant by the C99 standard was precisely what
C2011 says more clearly, but because there was no equivalent of 6.2.8p4,
that fact was much less obvious.
However, one thing was clear: in C99 alignment requirements were
described by only a single number, regardless of any uncertainty about
what that number meant. A struct x allocated in the way you describe
needs two parameters to describe the requirements it places on the
alignment of struct x objects: they must start 2 bytes before positions
that are multiples of 4 bytes. Therefore, an alignment requirement of
that type is clearly not what C99 was referring to when it talked about
alignment requirements.
 
Ad

Advertisements

B

Barry Schwarz

On 04/19/2012 01:09 PM, Barry Schwarz wrote:
...

That assumes there is no padding inserted between those two members.
While there is no good reason for a implementation to insert such
padding, there's also nothing in the standard to prohibit it. I would
strongly recommend against writing code that depends upon such
assumptions; particularly since you need to know details of particular
implementations of C to know which data type is the one with the
strictest alignment requirement.

You are right. Only when buffer is the first member is the alignment
guaranteed.
 
A

Andre

I have a structure defined as:

struct MyStruct {
<some fields of different types>
unsigned char buffer[MAX_BUFLEN];
};

The array buffer[] can store different types of variables: int, unsigned int, long, unsigned long,

null-terminated strings (of course, MAX_BUFLEN>= sizeof(long)).
Am I allowed to use a cast to long or int, as in the following instructions?
struct MyStruct s;
(long *)s.buffer = -100000L;
(unsigned long *)s.buffer = +100000UL;
(int *)s.buffer = -100;
(unsigned int *)s.buffer = +100U;
long l = *(long *)s.buffer;
unsigned long ul = *(unsigned long)s.buffer;
int i = *(int *)s.buffer;
unsigned int ui = *(unsigned int *)s.buffer;

I think this could work on some platforms, but is not fully portable (mostly on 16- and 32-bits).

It would work only if buffer[] field is correctly aligned in the
structure, but it's not guaranteed (

it may depends from the previous fields in the structure).
I think there are two solutions.
Avoiding to use cast and use memcpy (but I don't like it):
long l = -100000L;
unsigned long ul = 100000UL;
int i = -100;
unsigned int ui = +100;
memcpy(s.buffer,&l, sizeof(l));
memcpy(s.buffer,&ul, sizeof(ul));
memcpy(s.buffer,&i, sizeof(i));
memcpy(s.buffer,&ui, sizeof(ui));
memcpy(&l, s.buffer, sizeof(l));
memcpy(&ul, s.buffer, sizeof(ul));
memcpy(&i, s.buffer, sizeof(i));
memcpy(&ui, s.buffer, sizeof(ui));

Moving the buffer[] field at the top of the structure, so it is aligned for sure and I can use casting.

Another solution could be to define MyStruct as:

struct MyStruct {
<some fields of different types>
struct {
unsigned char buffer[MAX_BUFLEN];
} buf_aligned;
};

Are thre other solutions?

PS: I'm working on an embedded platform, so I don't have dynamic allocation malloc/free

(otherwise buffer could had be defined as a pointer and the memory space
could had be allocated

dynamically with malloc that surely returns aligned pointers).could you not fill in a dummy item that has a known alignment?

like
struct MyStruct {
<some fields of different types>
long dummy;
unsigned char buffer[MAX_BUFLEN];
};
 
B

Barry Schwarz

snip
could you not fill in a dummy item that has a known alignment?

like
struct MyStruct {
<some fields of different types>
long dummy;
unsigned char buffer[MAX_BUFLEN];
};

As already pointed out, there could be padding between dummy and
buffer, perverse but allowed nonetheless.
 
Ad

Advertisements

S

Stephen Sprunk

The C standard defines "alignment" as a "requirement that objects of a
particular type be located on storage boundaries with addresses that are
particular multiples of a byte address" (3.2p1). It also says "An
alignment is an implementation-defined integer value representing the
number of bytes between successive addresses at which a given object can
be allocated." (6.2.8p4),

Assume that struct x could be allocated in the way that you describe. It
could not be allocated on any address which is a multiple of 4; it can
only be allocated at positions which are odd multiples of 2. Therefore
_Alignof(struct x) can't be 4 - that would be inconsistent with 3.2p1.
Yet, the positions at which it can be placed are spaced 4 bytes apart,
so according to 6.2.8p4, _Alignof(struct x) must be 4. That assumption
leads to a contradiction, implying that the assumption must be false:
implementations are not allowed to allocate struct x objects in that
fashion.

Ah, that makes sense. Thanks.

Not that I ever thought anyone would be perverse enough to create such
an implementation, but sometimes it's handy to know exactly where the
line between "unlikely" and "prohibited" is.

S
 

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

Top