Hacker News new | past | comments | ask | show | jobs | submit login

> How would you do [packed structs] in C?

Bitfields! This is valid C:

  struct foo {
    unsigned bg_priority: 2;
    unsigned character_base: 2;
    // ...
  };



But C/ C-compilers don't guarantee your struct wont have holes (by default), so you may have to do something like __attribute__((packed)) to ensure they are packed structs:

    struct bitmap_file_header
    {
      UWord signature;
      UDWord file_size;
      UWord reserved_1;
      UWord reserved_2;
      UDWord file_offset_to_pixel_array;
    } __attribute__((packed));


This is not true of adjacent bitfields, at least for C99:

  An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit.
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 6.7.2.1 § 10


That’s usually something your ABI will describe in fairly precise terms, though if (as in your example) you want non-naturally-aligned fields, you may indeed want to both use a packed struct and prepare for alignment faults on less-tolerant architectures.


There’s also a directive (don’t have code in front of me) that you can do at file level that will cause all subsequent struct defs to be packed…

#push(pragma(pack(0)) ??

I’ve done a lot of direct register access in C this way. I do like Zigs ability to just define the different sizes though.


It’s MS(V)C syntax, now supported by GCC and Clang as well:

  #pragma pack(push)
  #pragma pack(1)
  /* ... */
  #pragma pack(pop)
The first two lines can also be condensed into

  #pragma pack(push, 1)


in microcontrollers it's very common to see code generated that creates structs for the registers. They will typically output fields that are a full machine word in size (or maybe in some cases as small as a byte), and individual bits will be addressed with bitmasking (ie `my_device.some_reg |= SOME_REG_FLAG_NAME` or `my_device.some_reg &= ~SOME_REG_FLAG_NAME` to clear it). It is sometimes necessary to be thoughtful about batching writes so that certain bits are set before the periferal begins some process. A trivial example would be:

  port_a.data_out |= GPIOA_PIN_1 | GPIOA_PIN_2;
and

  port_a.pin1 = true;
  port_a.pin2 = true;


This is why manufacturers don't do this for volatile register access. You now have bloated, hazard prone code with multiple read-modify-writes.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: