char data[0]

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jmcgill

    #16
    Re: char data[0]

    Keith Thompson wrote:
    Second, if you make a copy of the structure (even if you properly
    allow for the additional size), the data member will still point to
    the old copy.
    Take deep-copy semantics into account early in your design.

    Comment

    • Keith Thompson

      #17
      Re: char data[0]

      "Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
      Keith Thompson <kst-u@mib.orgwrote in message
      news:lnslhuwv7j .fsf@nuthaus.mi b.org...
      >"Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
      [...]
      Of course, you can allocate a "data" pointer contiguously in a struct
      in any event, right?
      >
      typedef struct {
      unsigned data_type;
      unsigned data_size;
      unsigned *data;
      } contiguous_data _struct;
      >
      contiguous_data _struct *my_contiguous_ data_struct;
      >
      void create_struct(u nsigned data_type,unsig ned data_size) {
      my_contiguous_d ata_struct=
      malloc(sizeof(c ontiguous_data_ struct)+(data_s ize*sizeof(unsi gned));
      my_contiguous_d ata_struct->data_type=data _type;
      my_contiguous_d ata_struct->data_size=data _size;
      my_contiguous_d ata_struct->data=
      my_contiguous_d ata_struct+size of(contiguous_d ata_struct);
      }
      >
      And now you may write the data to my_contiguous_d ata_struct->data(++).
      >[...]
      >>
      >I see two problems with this.
      >>
      Actually, as it turns out, there were at least a couple more, but
      who's counting?
      >
      >First, there's no guarantee that
      >my_contiguous_ data_struct+siz eof(contiguous_ data_struct)
      >
      s/be (void *)my_contiguous _data_struct+1
      >
      >is properly aligned.
      It took me a while to realize that "s/be" meant "should be". It's
      worth the effort to use whole words.

      And it should really be (void*)(my_cont iguous_data_str uct+1);
      otherwise you're adding 1 to a value of type void*, which is illegal
      (but gcc will accept it with no warning by default -- another reason
      why that extension is a bad idea).
      Now this confuses me...when you say "no guarantee" that the
      struct memory (?) is "properly aligned", what specifically are you
      talking about? The struct itself is aligned (within itself!), so doesn't
      that just leave any possible "alignment" of (in this case) a fundamental
      type? Is this just a pathological theoretical possibility, or something
      that could really happen?
      It could really happen. I'll construct an example similar to what you
      wrote above:

      #include <stdlib.h>

      struct contiguous_data {
      unsigned data_type;
      unsigned data_size;
      double *data;
      };

      struct contiguous_data *create_struct( unsigned data_type, unsigned data_size)
      {
      struct contiguous_data *result
      = malloc(sizeof(s truct contiguous_data ) +
      data_size * sizeof(double)) ;
      if (result == NULL) {
      return NULL;
      }
      result->data_type = data_type;
      result->data_size = data_size;
      result->data = (double*)(resul t + 1);
      return result;
      }

      Suppose types unsigned and (double*) are 4 bytes, requiring 4-byte
      alignment, and double is 8 bytes, requiring 8-byte alignment.
      Assuming struct contiguous_data has no gaps, its size is 12 bytes;
      let's say it requires 4-byte alignment. And suppose we call
      create_struct() with data_size == 2.

      Then create_struct() will malloc() 12 + 2*8 bytes, or 28 bytes. The
      base address of the malloc()ed block is guaranteed to be properly
      aligned for any type. We treat the first 12 bytes as a struct
      contiguous_data object, which is fine. We then treat the last 16
      bytes, starting at offset 12, as an array of 2 doubles -- but since 12
      is not a multiple of 8, it's not properly aligned to hold doubles.

      Misalignment might be less likely in your original example, but
      it's still possible.

      If you used the "struct hack", you'd declare:

      struct contiguous_data {
      unsigned data_type;
      unsigned data_size;
      double data[1];
      };

      (or "double data[];" if you use a C99 flexible array member). The
      compiler knows the required alignment of type double, so it inserts
      whatever padding is necessary. (We dropped the pointer, so it happens
      to be aligned anyway, but we could easily have an example where
      padding is necessary.)

      In your example, you placed the follow-on data manually without
      allowing for alignment issues. The compiler didn't have a chance to
      align it properly.
      >Second, if you make a copy of the structure (even if you properly
      >allow for the additional size), the data member will still point to
      >the old copy.
      >>
      Exactly, like memcpy() is a problem...but I openly stated that there
      were "caveats" concerning this "scheme"... I was just pointing out that
      you can "solve" the issue of "contiguous " memory and multiple free()s
      using it, that's all...
      Sure, but the struct hack is more convenient, even if it's of somewhat
      questionable validity.
      >The struct hack (or in C99, a flexible array member) avoids both these
      >problems.
      >>
      And if I don't have a C99 compiler, then that "hack" is just fine in all
      cases to use?
      Maybe. Probably.

      Question 2.6 in the FAQ says:

      Despite its popularity, the technique is also somewhat notorious:
      Dennis Ritchie has called it ``unwarranted chumminess with the C
      implementation, '' and an official interpretation has deemed that
      it is not strictly conforming with the C Standard, although it
      does seem to work under all known implementations . (Compilers
      which check array bounds carefully might issue warnings.)

      If you don't trust the struct hack, you can always just allocate the
      data separately:

      #include <stdlib.h>

      struct contiguous_data {
      unsigned data_type;
      unsigned data_size;
      double *data;
      };

      struct contiguous_data *create_struct( unsigned data_type, unsigned data_size)
      {
      struct contiguous_data *result = malloc(sizeof *result);
      if (result == NULL) {
      return NULL;
      }
      result->data_type = data_type;
      result->data_size = data_size;
      result->data = malloc(data_siz e * sizeof(double)) ;
      if (result->data == NULL) {
      free(result);
      return NULL;
      }
      return result;
      }

      This will require two calls to free() to deallocate the allocated
      memory.

      --
      Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
      San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
      We must do something. This is something. Therefore, we must do this.

      Comment

      • Harald van Dijk

        #18
        Re: char data[0]

        Keith Thompson wrote:
        "Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
        Keith Thompson <kst-u@mib.orgwrote in message
        news:lnslhuwv7j .fsf@nuthaus.mi b.org...
        "Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
        [...]
        Of course, you can allocate a "data" pointer contiguously in a struct
        in any event, right?

        typedef struct {
        unsigned data_type;
        unsigned data_size;
        unsigned *data;
        } contiguous_data _struct;

        contiguous_data _struct *my_contiguous_ data_struct;

        void create_struct(u nsigned data_type,unsig ned data_size) {
        my_contiguous_d ata_struct=
        malloc(sizeof(c ontiguous_data_ struct)+(data_s ize*sizeof(unsi gned));
        my_contiguous_d ata_struct->data_type=data _type;
        my_contiguous_d ata_struct->data_size=data _size;
        my_contiguous_d ata_struct->data=
        my_contiguous_d ata_struct+size of(contiguous_d ata_struct);
        }

        And now you may write the data to my_contiguous_d ata_struct->data(++).
        [...]
        >
        I see two problems with this.
        >
        Actually, as it turns out, there were at least a couple more, but
        who's counting?
        First, there's no guarantee that
        my_contiguous_d ata_struct+size of(contiguous_d ata_struct)
        s/be (void *)my_contiguous _data_struct+1
        is properly aligned.
        >
        It took me a while to realize that "s/be" meant "should be". It's
        worth the effort to use whole words.
        >
        And it should really be (void*)(my_cont iguous_data_str uct+1);
        otherwise you're adding 1 to a value of type void*, which is illegal
        (but gcc will accept it with no warning by default -- another reason
        why that extension is a bad idea).
        >
        Now this confuses me...when you say "no guarantee" that the
        struct memory (?) is "properly aligned", what specifically are you
        talking about? The struct itself is aligned (within itself!), so doesn't
        that just leave any possible "alignment" of (in this case) a fundamental
        type? Is this just a pathological theoretical possibility, or something
        that could really happen?
        >
        It could really happen. I'll construct an example similar to what you
        wrote above:
        >
        #include <stdlib.h>
        >
        struct contiguous_data {
        unsigned data_type;
        unsigned data_size;
        double *data;
        };
        >
        struct contiguous_data *create_struct( unsigned data_type, unsigned data_size)
        {
        struct contiguous_data *result
        = malloc(sizeof(s truct contiguous_data ) +
        data_size * sizeof(double)) ;
        if (result == NULL) {
        return NULL;
        }
        result->data_type = data_type;
        result->data_size = data_size;
        result->data = (double*)(resul t + 1);
        return result;
        }
        >
        Suppose types unsigned and (double*) are 4 bytes, requiring 4-byte
        alignment, and double is 8 bytes, requiring 8-byte alignment.
        Assuming struct contiguous_data has no gaps, its size is 12 bytes;
        let's say it requires 4-byte alignment. And suppose we call
        create_struct() with data_size == 2.
        >
        Then create_struct() will malloc() 12 + 2*8 bytes, or 28 bytes. The
        base address of the malloc()ed block is guaranteed to be properly
        aligned for any type. We treat the first 12 bytes as a struct
        contiguous_data object, which is fine. We then treat the last 16
        bytes, starting at offset 12, as an array of 2 doubles -- but since 12
        is not a multiple of 8, it's not properly aligned to hold doubles.
        >
        Misalignment might be less likely in your original example, but
        it's still possible.
        All structs are required to have the same alignment, right? Since the
        initial member of any struct can be of any type, isn't it then required
        that any struct is aligned properly for any type? And if that is, isn't
        one past the end of any struct required to be aligned properly for any
        type as well, in order for arrays of structs to work?

        (I know I'm probably overlooking something, but I don't know what.)

        Comment

        • Keith Thompson

          #19
          Re: char data[0]

          "Harald van Dijk" <truedfx@gmail. comwrites:
          [...]
          All structs are required to have the same alignment, right?
          No. The standard does say that

          All pointers to structure types shall have the same representation
          and alignment requirements as each other.

          but that refers to the alignment of pointer objects, not to the
          alignment of structure objects.

          For example, this type:

          struct foo {
          char c;
          };

          can reasonably have a size and alignment of 1 byte.

          --
          Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
          San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
          We must do something. This is something. Therefore, we must do this.

          Comment

          • Andrey Tarasevich

            #20
            Re: char data[0]

            Harald van Dijk wrote:
            ...
            All structs are required to have the same alignment, right? Since the
            initial member of any struct can be of any type, isn't it then required
            that any struct is aligned properly for any type?
            No. Why? The only thing that is required is that each given struct is
            properly aligned for its own and only its own members. The alignment
            requirement of the struct itself is indeed determined by its first
            member, since other members can be aligned independently by introducing
            internal padding.

            On a related note, the trailing padding (the one that follows the last
            member) is introduced in order achieve proper alignment of struct
            elements in an array and, therefore, can be thought of as dependent on
            all members of the structure. This means that if you want to use this
            technique to store an array of 'int's immediately after the struct in
            memory, you should be OK if the struct itself contains at least one
            'int' member (or a member with a stronger alignment requirement).
            Otherwise, there's no guarantee.

            --
            Best regards,
            Andrey Tarasevich

            Comment

            • Andrey Tarasevich

              #21
              Re: char data[0]

              jmcgill wrote:
              Keith Thompson wrote:
              >
              >Second, if you make a copy of the structure (even if you properly
              >allow for the additional size), the data member will still point to
              >the old copy.
              >
              Take deep-copy semantics into account early in your design.
              Frivolous and trigger-happy introduction of absolutely unnecessary and
              unnatural levels of indirection in data structures lead to design
              errors. Especially if done early in the design.

              --
              Best regards,
              Andrey Tarasevich

              Comment

              • Harald van Dijk

                #22
                Re: char data[0]

                Keith Thompson wrote:
                "Harald van Dijk" <truedfx@gmail. comwrites:
                [...]
                All structs are required to have the same alignment, right?
                >
                No. The standard does say that
                >
                All pointers to structure types shall have the same representation
                and alignment requirements as each other.
                >
                but that refers to the alignment of pointer objects, not to the
                alignment of structure objects.
                That was actually in part what I was thinking of, but for a different
                reason. How can pointers to structure types with different alignment
                requirements have the same representation? The standard doesn't say the
                corresponding signed and unsigned integer types have the same
                representation, so I find it hard to believe it's meant to say that
                only the representations for values valid for both types are the same.
                It does say the representation of all integer types in #if expressions
                are the same as that of intmax_t or uintmax_t, and for that, it's clear
                that it refers to which values can be held by the types.
                For example, this type:
                >
                struct foo {
                char c;
                };
                >
                can reasonably have a size and alignment of 1 byte.
                Let's say that it does, and that the size and alignment of int, or a
                structure containing only an int, is 2 bytes.

                #include <stdlib.h>
                #include <string.h>
                struct c {
                char c;
                };
                struct i {
                int i;
                };

                int main(void) {
                struct c c;
                struct c *pc1 = &c;
                struct c *pc2 = &c + 1;
                /* if struct i is allowed to have, and has, stricter alignment
                requirements */
                /* than struct c, either pc1 is not properly aligned for it, or pc2
                is not */

                struct i *pi1, *pi2;

                memcpy(&pi1, &pc1, sizeof pc1);
                memcpy(&pi2, &pc2, sizeof pc2);
                printf("%p\n", (void *) pi1, (void *) pi2);
                /* 1 */

                pi1 = (struct i *) pc1;
                pi2 = (struct i *) pc2;
                /* 2 */
                printf("%p\n", (void *) pi1, (void *) pi2);
                }

                At /*1*/, has there been undefined behaviour? If not, how about at
                /*2*/? I believe the answers with the given alignment requirements are
                no for /*1*/, and yes for /*2*/, but if that's the case, what's the
                benefit of making /*2*/ undefined in the first place?

                Comment

                • CBFalconer

                  #23
                  Re: char data[0]

                  Harald van D?k wrote:
                  >
                  .... snip ...
                  >
                  All structs are required to have the same alignment, right? Since
                  the initial member of any struct can be of any type, isn't it then
                  required that any struct is aligned properly for any type? And if
                  that is, isn't one past the end of any struct required to be
                  aligned properly for any type as well, in order for arrays of
                  structs to work?
                  >
                  (I know I'm probably overlooking something, but I don't know what.)
                  Using the struct hack:

                  struct foo {
                  T bar;
                  char foobar[1];
                  }

                  "sizeof (struct foo)" will reflect that alignment and will have to
                  make anything assigned after the struct suitably aligned for a T.
                  However offsetof(struct foo, foobar) will not. Thus you can't use
                  the foobar component for things that may require anything other
                  than char alignment. This doesn't apply to the C99 use of "char
                  foobar[]".

                  --
                  Some informative links:
                  <news:news.anno unce.newusers
                  <http://www.geocities.c om/nnqweb/>
                  <http://www.catb.org/~esr/faqs/smart-questions.html>
                  <http://www.caliburn.nl/topposting.html >
                  <http://www.netmeister. org/news/learn2quote.htm l>
                  <http://cfaj.freeshell. org/google/>


                  Comment

                  • Bill Reid

                    #24
                    Re: char data[0]


                    Keith Thompson <kst-u@mib.orgwrote in message
                    news:lnk636uuzv .fsf@nuthaus.mi b.org...
                    "Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
                    Keith Thompson <kst-u@mib.orgwrote in message
                    news:lnslhuwv7j .fsf@nuthaus.mi b.org...
                    "Bill Reid" <hormelfree@hap pyhealthy.netwr ites:
                    [...]
                    Of course, you can allocate a "data" pointer contiguously in a struct
                    in any event, right?

                    typedef struct {
                    unsigned data_type;
                    unsigned data_size;
                    unsigned *data;
                    } contiguous_data _struct;

                    contiguous_data _struct *my_contiguous_ data_struct;

                    void create_struct(u nsigned data_type,unsig ned data_size) {
                    my_contiguous_d ata_struct=
                    malloc(sizeof(c ontiguous_data_ struct)+(data_s ize*sizeof(unsi gned));
                    my_contiguous_d ata_struct->data_type=data _type;
                    my_contiguous_d ata_struct->data_size=data _size;
                    my_contiguous_d ata_struct->data=
                    my_contiguous_d ata_struct+size of(contiguous_d ata_struct);
                    }

                    And now you may write the data to
                    my_contiguous_d ata_struct->data(++).
                    [...]
                    >
                    I see two problems with this.
                    >
                    Actually, as it turns out, there were at least a couple more, but
                    who's counting?
                    First, there's no guarantee that
                    my_contiguous_d ata_struct+size of(contiguous_d ata_struct)
                    s/be (void *)my_contiguous _data_struct+1
                    is properly aligned.
                    >
                    It took me a while to realize that "s/be" meant "should be". It's
                    worth the effort to use whole words.
                    >
                    THAT'S a pretty common usage...
                    And it should really be (void*)(my_cont iguous_data_str uct+1);
                    otherwise you're adding 1 to a value of type void*, which is illegal
                    (but gcc will accept it with no warning by default -- another reason
                    why that extension is a bad idea).
                    >
                    Ah yes, in another post my actual working code was listed as:

                    (*csv_efileb)->buffer=(void *)(*csv_efileb+ 1);

                    when dealing with a pointer to a pointer passed as an argument...
                    Now this confuses me...when you say "no guarantee" that the
                    struct memory (?) is "properly aligned", what specifically are you
                    talking about? The struct itself is aligned (within itself!), so
                    doesn't
                    that just leave any possible "alignment" of (in this case) a fundamental
                    type? Is this just a pathological theoretical possibility, or something
                    that could really happen?
                    >
                    It could really happen. I'll construct an example similar to what you
                    wrote above:
                    >
                    Well, in the interim I answered my own question, and more. The
                    issue for most systems today is "self-alignment" for all types, and the
                    bottom line as I take it is that you can't have a larger size for your
                    "data" than the largest size in the struct. (If you had a couple of
                    unsigned chars in the struct, and a "data buffer" of doubles, you'd
                    be hosed.) Soooo, I'm quite sure the following would create a
                    big mess on my machine (though all the examples I've given would
                    work on most all machines):
                    #include <stdlib.h>
                    >
                    struct contiguous_data {
                    unsigned data_type;
                    unsigned data_size;
                    double *data;
                    };
                    >
                    Yeah, your data is bigger than the biggest size in the struct itself.
                    NG (that means "No(t) Good" or "No Go").
                    struct contiguous_data *create_struct( unsigned data_type, unsigned
                    data_size)
                    {
                    struct contiguous_data *result
                    = malloc(sizeof(s truct contiguous_data ) +
                    data_size * sizeof(double)) ;
                    if (result == NULL) {
                    return NULL;
                    }
                    result->data_type = data_type;
                    result->data_size = data_size;
                    result->data = (double*)(resul t + 1);
                    return result;
                    }
                    >
                    Suppose types unsigned and (double*) are 4 bytes, requiring 4-byte
                    alignment, and double is 8 bytes, requiring 8-byte alignment.
                    Assuming struct contiguous_data has no gaps, its size is 12 bytes;
                    let's say it requires 4-byte alignment. And suppose we call
                    create_struct() with data_size == 2.
                    >
                    Then create_struct() will malloc() 12 + 2*8 bytes, or 28 bytes. The
                    base address of the malloc()ed block is guaranteed to be properly
                    aligned for any type. We treat the first 12 bytes as a struct
                    contiguous_data object, which is fine. We then treat the last 16
                    bytes, starting at offset 12, as an array of 2 doubles -- but since 12
                    is not a multiple of 8, it's not properly aligned to hold doubles.
                    >
                    Misalignment might be less likely in your original example, but
                    it's still possible.
                    >
                    As I take it, if you are dealing with chars as "data", you're pretty
                    much OK in like 99% of the cases...
                    If you used the "struct hack", you'd declare:
                    >
                    struct contiguous_data {
                    unsigned data_type;
                    unsigned data_size;
                    double data[1];
                    };
                    >
                    (or "double data[];" if you use a C99 flexible array member).
                    Well, as it turns out, I learned many things today, and one of them
                    is that my compiler, although obstensibly NOT "C99" compliant, offers
                    the "flexible array member" (SHOULD BE: "indetermin ate array as the
                    last member of a struct") feature "as a special extension to the ANSI
                    standard". I should have known, because they have all kinds of goofy
                    stuff like that in there, but I first experimented by changing some working
                    code as follows:

                    typedef struct {
                    unsigned type;
                    unsigned long size;
                    unsigned cols;
                    unsigned rows;
                    char *buffer;
                    } CSV_EFILEB;

                    to

                    typedef struct {
                    unsigned type;
                    unsigned long size;
                    unsigned cols;
                    unsigned rows;
                    char buffer[];
                    } CSV_EFILEB;

                    And VOILA (that's like Italian or something, sorry), the whole thing
                    worked slicker than a bannana slug trail!
                    The
                    compiler knows the required alignment of type double, so it inserts
                    whatever padding is necessary. (We dropped the pointer, so it happens
                    to be aligned anyway, but we could easily have an example where
                    padding is necessary.)
                    >
                    Yeah, but for the sake of pure expediancy and correctness, I guess
                    I should just use "indetermin ate arrays as a final member of struct",
                    aside from any potential "backwards-compatibility" issues...
                    In your example, you placed the follow-on data manually without
                    allowing for alignment issues. The compiler didn't have a chance to
                    align it properly.
                    >
                    Second, if you make a copy of the structure (even if you properly
                    allow for the additional size), the data member will still point to
                    the old copy.
                    >
                    Exactly, like memcpy() is a problem...but I openly stated that there
                    were "caveats" concerning this "scheme"... I was just pointing out that
                    you can "solve" the issue of "contiguous " memory and multiple free()s
                    using it, that's all...
                    >
                    Sure, but the struct hack is more convenient, even if it's of somewhat
                    questionable validity.
                    >
                    The struct hack (or in C99, a flexible array member) avoids both these
                    problems.
                    >
                    Yes, it does...and I'll be experimenting a little more to see just how
                    "flexible" it really is...stuff like arrays of void pointers to be cast into
                    different struct types, you know...
                    And if I don't have a C99 compiler, then that "hack" is just fine in all
                    cases to use?
                    >
                    Maybe. Probably.
                    >
                    Question 2.6 in the FAQ says:
                    >
                    Despite its popularity, the technique is also somewhat notorious:
                    Dennis Ritchie has called it ``unwarranted chumminess with the C
                    implementation, '' and an official interpretation has deemed that
                    it is not strictly conforming with the C Standard, although it
                    does seem to work under all known implementations . (Compilers
                    which check array bounds carefully might issue warnings.)
                    >
                    I think they also allowed possible "pathologic al" POTENTIAL
                    alignment issues, though again, not with type char as "data"...
                    If you don't trust the struct hack, you can always just allocate the
                    data separately:
                    >
                    #include <stdlib.h>
                    >
                    struct contiguous_data {
                    unsigned data_type;
                    unsigned data_size;
                    double *data;
                    };
                    >
                    struct contiguous_data *create_struct( unsigned data_type, unsigned
                    data_size)
                    {
                    struct contiguous_data *result = malloc(sizeof *result);
                    if (result == NULL) {
                    return NULL;
                    }
                    result->data_type = data_type;
                    result->data_size = data_size;
                    result->data = malloc(data_siz e * sizeof(double)) ;
                    if (result->data == NULL) {
                    free(result);
                    return NULL;
                    }
                    return result;
                    }
                    >
                    This will require two calls to free() to deallocate the allocated
                    memory.
                    >
                    That's SOOOOOOO much work...

                    ---
                    William Ernest Reid



                    Comment

                    • Bill Reid

                      #25
                      Re: char data[0]


                      Andrey Tarasevich <andreytarasevi ch@hotmail.comw rote in message
                      news:12irtkoh3j v0ta6@news.supe rnews.com...
                      Harald van D?k wrote:
                      ...
                      All structs are required to have the same alignment, right? Since the
                      initial member of any struct can be of any type, isn't it then required
                      that any struct is aligned properly for any type?
                      >
                      No. Why? The only thing that is required is that each given struct is
                      properly aligned for its own and only its own members. The alignment
                      requirement of the struct itself is indeed determined by its first
                      member, since other members can be aligned independently by introducing
                      internal padding.
                      >
                      As I learned the hard way (reading the FAQ) last night, structs are
                      actually "self-aligned" (translation: "start at") "by their most restrictive
                      member", meaning the largest type in the struct (or this is how I
                      understand it).

                      Of course, the way you say it actually makes more sense, so maybe
                      I'm just confused AGAIN...on the other hand, the compiler COULD
                      easily adjust all the internal struct padding to conform to the above
                      "self-alignment" rule for any given struct, so maybe THAT makes
                      more sense...

                      ---
                      William Ernest Reid



                      Comment

                      • Chris Dollin

                        #26
                        Re: char data[0]

                        Bill Reid wrote:
                        As I learned the hard way (reading the FAQ) last night, structs are
                        actually "self-aligned" (translation: "start at") "by their most restrictive
                        member", meaning the largest type in the struct (or this is how I
                        understand it).
                        Which bit of the FAQ reads like that?

                        --
                        Chris "Essen -7 and counting" Dollin
                        "A facility for quotation covers the absence of original thought." /Gaudy Night/

                        Comment

                        • Bill Reid

                          #27
                          Re: char data[0]


                          Chris Dollin <chris.dollin@h p.comwrote in message
                          news:eglkil$v0b $1@malatesta.hp l.hp.com...
                          Bill Reid wrote:
                          >
                          As I learned the hard way (reading the FAQ) last night, structs are
                          actually "self-aligned" (translation: "start at") "by their most
                          restrictive
                          member", meaning the largest type in the struct (or this is how I
                          understand it).
                          >
                          Which bit of the FAQ reads like that?
                          >
                          2.12, "Additional Links"->Eric Raymond post:

                          On modern 32-bit machines like the SPARC or the Intel [34]86, or
                          any Motorola chip from the 68020 up, each data iten must usually be
                          ``self-aligned'', beginning on an address that is a multiple of its type
                          size.
                          Thus, 32-bit types must begin on a 32-bit boundary, 16-bit types on a
                          16-bit boundary, 8-bit types may begin anywhere, struct/array/union
                          types have the alignment of their most restrictive member.

                          ---end of excerpt

                          So as I take it, compilers on most 32-bit machines today set up
                          struct alignment based on the aligment of "their most restrictive member".

                          Discuss among yourselves...cu rrently, I'm still wondering how to
                          set up a "contiguous data struct" with the idea of casting the "data"
                          to any number of different types, something I've wondered about
                          for a long time...

                          ---
                          William Ernest Reid



                          Comment

                          • pete

                            #28
                            Re: char data[0]

                            Bill Reid wrote:
                            >
                            Chris Dollin <chris.dollin@h p.comwrote in message
                            news:eglkil$v0b $1@malatesta.hp l.hp.com...
                            Bill Reid wrote:
                            As I learned the hard way (reading the FAQ) last night, structs are
                            actually "self-aligned" (translation: "start at") "by their most
                            restrictive
                            member", meaning the largest type in the struct (or this is how I
                            understand it).
                            Which bit of the FAQ reads like that?
                            2.12, "Additional Links"->Eric Raymond post:
                            >
                            On modern 32-bit machines like the SPARC or the Intel [34]86, or
                            any Motorola chip from the 68020 up, each data iten must usually be
                            ``self-aligned'', beginning on an address that is a multiple of its type
                            size.
                            Thus, 32-bit types must begin on a 32-bit boundary, 16-bit types on a
                            16-bit boundary, 8-bit types may begin anywhere, struct/array/union
                            types have the alignment of their most restrictive member.
                            >
                            ---end of excerpt
                            >
                            So as I take it, compilers on most 32-bit machines today set up
                            struct alignment based on
                            the aligment of "their most restrictive member".
                            Padding bytes, enable member alignment
                            to be independant of struct alignment,
                            except for the first member.

                            --
                            pete

                            Comment

                            • Harald van Dijk

                              #29
                              Re: char data[0]

                              pete wrote:
                              Padding bytes, enable member alignment
                              to be independant of struct alignment,
                              except for the first member.
                              Well, the member must be aligned, it must be at a constant offset from
                              the start of the structure, and the result of malloc() must both be
                              properly aligned for the member type as well as for the whole struct.

                              Comment

                              • pete

                                #30
                                Re: char data[0]

                                =?utf-8?B?SGFyYWxkIHZ hbiBExLNr?= wrote:
                                >
                                pete wrote:
                                Padding bytes, enable member alignment
                                to be independant of struct alignment,
                                except for the first member.
                                >
                                Well, the member must be aligned, it must be at a constant offset from
                                the start of the structure, and the result of malloc() must both be
                                properly aligned for the member type as well as for the whole struct.
                                With suitable padding bytes,
                                a struct with a first member of type char,
                                could be aligned at any address,
                                no matter what type the other members were.

                                If you had 4 byte ints and a struct type
                                {
                                char X;
                                int Y;
                                }

                                you could have
                                X followed by 3 padding bytes
                                followed by Y
                                for a struct alignment where the struct was aligned for type int.

                                If the struct was aligned on the next byte then
                                X followed by 2 padding bytes
                                followed by Y
                                followed by 1 padding byte would work.

                                If the struct was aligned on the byte after that then
                                X followed by 1 padding byte
                                followed by Y
                                followed by 2 padding bytes would work.

                                And if the stuct was aligned on the next byte after that then
                                X contiguous with Y
                                followed by 3 padding bytes would work.

                                --
                                pete

                                Comment

                                Working...