How to be sure a structure field is aligned

Discussion in 'C Programming' started by pozzugno@gmail.com, Apr 19, 2012.

  1. Guest

    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).
     
    , Apr 19, 2012
    #1
    1. Advertising

  2. Ian Collins Guest

    On 04/19/12 07:45 PM, 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.

    --
    Ian Collins
     
    Ian Collins, Apr 19, 2012
    #2
    1. Advertising

  3. Guest

    Il giorno giovedì 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
    > On 04/19/12 07:45 PM, 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 continuehaving the alignment problem on buffer.
     
    , Apr 19, 2012
    #3
  4. Ian Collins Guest

    On 04/19/12 09:01 PM, wrote:
    > Il giorno giovedì 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
    >> On 04/19/12 07:45 PM, 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.

    --
    Ian Collins
     
    Ian Collins, Apr 19, 2012
    #4
  5. James Kuyper Guest

    On 04/19/2012 06:30 AM, Ian Collins wrote:
    > On 04/19/12 09:01 PM, wrote:
    >> Il giorno gioved� 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
    >>> On 04/19/12 07:45 PM, 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"?
    --
    James Kuyper
     
    James Kuyper, Apr 19, 2012
    #5
  6. Ian Collins Guest

    On 04/19/12 10:35 PM, James Kuyper wrote:
    > On 04/19/2012 06:30 AM, Ian Collins wrote:
    >> On 04/19/12 09:01 PM, wrote:
    >>> Il giorno gioved� 19 aprile 2012 10:02:56 UTC+2, Ian Collins ha scritto:
    >>>> On 04/19/12 07:45 PM, 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...

    --
    Ian Collins
     
    Ian Collins, Apr 19, 2012
    #6
  7. James Kuyper Guest

    On 04/19/2012 03:45 AM, 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)).
    >
    > 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.

    --
    James Kuyper
     
    James Kuyper, Apr 19, 2012
    #7
  8. James Kuyper Guest

    On 04/19/2012 06:42 AM, Ian Collins wrote:
    > On 04/19/12 10:35 PM, James Kuyper wrote:
    >> On 04/19/2012 06:30 AM, Ian Collins wrote:

    ....
    >>> 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...


    You're in zone +12? Get some sleep. I just woke up.
    --
    James Kuyper
     
    James Kuyper, Apr 19, 2012
    #8
  9. Guest

    Il giorno giovedì 19 aprile 2012 13:02:33 UTC+2, James Kuyper ha scritto:
    > On 04/19/2012 03:45 AM, 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 :-(


    > > Are thre other solutions?

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

    [...]

    Yes, this is THE SOLUTION! Thank you very much.
     
    , Apr 19, 2012
    #9
  10. On Thu, 19 Apr 2012 07:53:20 -0700 (PDT), wrote:

    >Il giorno giovedì 19 aprile 2012 13:02:33 UTC+2, James Kuyper ha scritto:
    >> On 04/19/2012 03:45 AM, 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.

    --
    Remove del for email
     
    Barry Schwarz, Apr 19, 2012
    #10
  11. Joe Pfeiffer Guest

    writes:

    > 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?
     
    Joe Pfeiffer, Apr 19, 2012
    #11
  12. James Kuyper Guest

    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.
     
    James Kuyper, Apr 19, 2012
    #12
  13. On 19-Apr-12 12:09, Barry Schwarz wrote:
    > On Thu, 19 Apr 2012 07:53:20 -0700 (PDT), wrote:
    >> 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.


    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

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
     
    Stephen Sprunk, Apr 19, 2012
    #13
  14. James Kuyper Guest

    On 04/19/2012 03:26 PM, Stephen Sprunk wrote:
    > On 19-Apr-12 12:09, Barry Schwarz wrote:

    ....
    >> 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.


    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.
     
    James Kuyper, Apr 19, 2012
    #14
  15. On 19-Apr-12 14:56, James Kuyper wrote:
    > On 04/19/2012 03:26 PM, Stephen Sprunk wrote:
    >> On 19-Apr-12 12:09, Barry Schwarz wrote:

    > ...
    >>> 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.

    >
    > 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

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
     
    Stephen Sprunk, Apr 19, 2012
    #15
  16. James Kuyper Guest

    On 04/19/2012 04:30 PM, Stephen Sprunk wrote:
    > On 19-Apr-12 14:56, James Kuyper wrote:

    ....
    >> 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?


    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.

    >> 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?


    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.
     
    James Kuyper, Apr 19, 2012
    #16
  17. On Thu, 19 Apr 2012 14:12:33 -0400, James Kuyper
    <> wrote:

    >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.


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

    --
    Remove del for email
     
    Barry Schwarz, Apr 19, 2012
    #17
  18. Andre Guest

    On 19.04.2012 09:45, 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)).
    >
    > 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];
    };
     
    Andre, Apr 20, 2012
    #18
  19. On Fri, 20 Apr 2012 13:37:39 +0200, Andre <> wrote:


    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.

    --
    Remove del for email
     
    Barry Schwarz, Apr 20, 2012
    #19
  20. On 19-Apr-12 16:34, James Kuyper wrote:
    > On 04/19/2012 04:30 PM, Stephen Sprunk wrote:
    >> 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.


    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

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
     
    Stephen Sprunk, Apr 20, 2012
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page