Re: Pre-offsetof() question

From: Eric Sosman (Eric.Sosman_at_sun.com)
Date: 10/06/03


Date: Mon, 06 Oct 2003 16:26:40 -0400


"Arthur J. O'Dwyer" wrote:
>
> As far as I know, C89/C90 did not contain the
> now-standard offsetof() macro.

    Full stop: C89 invented the <stddef.h> header, and specified
that it must provide offsetof().

> Did C89 mandate that structs had to have a consistent
> layout? For example, consider the typical layout of
> the following structure:
>
> struct weird
> {
> int x; /* sizeof(int)==4 here */
> double y; /* sizeof(double)==8 here */
> int z;
> };
>
> Now, let's suppose that the target architecture has typical
> 80x86 alignment requirements, where 'int' aligns on 4-byte
> boundaries and 'double' on 8-byte boundaries.
> A C99 compiler might produce a layout that looked like
> this:
>
> |_x__|####|___y____|_z__|####|
>
> sizeof (struct weird) == 24 bytes
>
> But could a C89, pre-offsetof() compiler decide to make
> the layout of the struct vary, like this:
>
> |_x__|####|___y____|_z__| on 8-byte alignment
>
> |_x__|___y____|####|_z__| on 4-byte alignment
>
> sizeof (struct weird) == 20 bytes
>
> Note that the relative ordering of the members is
> preserved; each 'struct weird' has the same size in
> bytes; and all objects are properly aligned for their
> type. But the "weird" ordering has saved us 4 bytes
> per structure!
>
> Does C89 allow this, or is it disallowed by something
> in that standard? If so, what?

    No version of the Standard describes what alignments
are to be enforced. However, the rules for compatibility
of types guarantee that the same struct type will have the
same arrangement of padding bytes in all translation units.

    Could this arrangement be different depending on flags
calling for different "strictnesses" of alignment? Yes, of
course -- but this isn't a contradiction, because using a
different set of compiler flags gives you a different
implementation of C, and the Standard makes no requirement
that translation units compiled by different implementations
must interoperate.

    By the way, note that your 8-byte alignment example is
faulty. If a double must be aligned to an 8-byte boundary,
the sizeof a struct containing a double must be a multiple
of 8 bytes. Otherwise, you would not be able to malloc()
an array of two such structs:

        struct weird *p = malloc(2 * sizeof *p); // assume 40

        0 4 8 16 20 24 28 36 40
        |_x__|####|___y____|_z__|_x__|####|___y____|_z__|
        ^ ^
        | |
        p p+1

Note that (p+1)->y is mis-aligned.

-- 
Eric.Sosman@sun.com


Relevant Pages

  • Re: Casting Byte Buffer returned from CeReadRecordPropsEx to CEPROPVAL in C#
    ... use explicit layout and put the members where you need them. ... UInt16 uiVal; // UInt16 ... IntPtr tmp = new IntPtr; ... internal struct CEBLOB ...
    (microsoft.public.pocketpc.developer)
  • Re: Casting Byte Buffer returned from CeReadRecordPropsEx to CEPROPVAL in C#
    ... use explicit layout and put the members where you need them. ... UInt16 uiVal; // UInt16 ... IntPtr tmp = new IntPtr; ... internal struct CEBLOB ...
    (microsoft.public.pocketpc.developer)
  • Re: [RFC] x86: xsave/xrstor support, ucontext_t extensions
    ... Appended patch adds the support for xsave/xrstor infrastructure for x86. ... only user-space consumer of kernel types: there are other libcs, ... struct sigcontext uc_mcontext; ... You're changing the layout of struct ucontext in two ways: ...
    (Linux-Kernel)
  • Re: union field length mismatch
    ... >> I can't really think of a case where the compiler ... >> can safely change the layout of a struct without ... > If the struct type is static, it should be safe: ...
    (comp.os.linux.development.system)
  • Re: Structure size directives
    ... struct foo { ... The fact that MANY compilers give the programmer ... The best way for the compiler to give the programmer a way to specifiy ... forcing a structure layout to meet some external constraint may be. ...
    (comp.lang.c)