1. 6
  1.  

  2. 5

    So, yeah, this, as presented in the article, is a bad idea.

    char buf[BIG_ENOUG_SIZE];
    struct something *foo;
    struct something_else *bar;
    
    // point foo to the beginning of buf
    foo = (struct something *) buf;
    // point bar to the location after foo inside buf
    bar = (struct something_else *) (buf + sizeof(struct something));
    

    You can’t be certain that everything is going to align properly here, namely on the border between the struct something and struct something_else.

    The article advocates for this because otherwise you use twice the memory. Is that extra memory on the stack? In that case, it may not matter. If you don’t have a stack (and lots of 8-bit microcontrollers don’t), then do yourself a favour and do this instead:

    struct concated_stuff {
      struct something { ... };
      struct something_else { ... };
    };
    

    And honestly, there doesn’t seem to be a good reason why they have to be adjacent in memory in the first place. [edit: the article does offhandedly mention that “it needs them concatenated into a single buffer”. Sounds dubious, but it’s not explained, so I’ll let it slide.] So just declare them as static globals and don’t worry about it.

    1. 1

      Another option I would think is to use a flexible array member inside struct something like this:

      struct something {
           int something_field1;
           char *something_field2;
      
           char cls_extra[];
      };
      

      Then when allocating later in your code:

      struct something *sthing = malloc(sizeof(struct something) + sizeof(struct something_else));
      
      struct something_else *selse = (struct something_else *)sthing->cls_extra;
      

      Or would that also have the same alignment issues? I was under the impression that Microsoft Windows API uses this trick (well the older way pre-dating C99) in some APIs as mentioned on Old New Thing.

      1. 1

        I think that one might be okay, since cls_extra is now aligned as a pointer, but there might still be some weird layout that would cause a problem.

        Bear in mind the article is writing in the context of 8-bit microcontrollers, so there are two things to consider: the size of things tends to be not what you think (and thus alignment can be bizarre), and use of malloc is practically forbidden. (If you don’t have a stack, you probably don’t have a heap, either.)