Is gcc's __attribute__((packed)) / #pragma pack unsafe?

前端 未结 5 1253
广开言路
广开言路 2020-11-22 03:48

In C, the compiler will lay out members of a struct in the order in which they\'re declared, with possible padding bytes inserted between members, or after the last member,

5条回答
  •  长发绾君心
    2020-11-22 04:26

    (The following is a very artificial example cooked up to illustrate.) One major use of packed structs is where you have a stream of data (say 256 bytes) to which you wish to supply meaning. If I take a smaller example, suppose I have a program running on my Arduino which sends via serial a packet of 16 bytes which have the following meaning:

    0: message type (1 byte)
    1: target address, MSB
    2: target address, LSB
    3: data (chars)
    ...
    F: checksum (1 byte)
    

    Then I can declare something like

    typedef struct {
      uint8_t msgType;
      uint16_t targetAddr; // may have to bswap
      uint8_t data[12];
      uint8_t checksum;
    } __attribute__((packed)) myStruct;
    

    and then I can refer to the targetAddr bytes via aStruct.targetAddr rather than fiddling with pointer arithmetic.

    Now with alignment stuff happening, taking a void* pointer in memory to the received data and casting it to a myStruct* will not work unless the compiler treats the struct as packed (that is, it stores data in the order specified and uses exactly 16 bytes for this example). There are performance penalties for unaligned reads, so using packed structs for data your program is actively working with is not necessarily a good idea. But when your program is supplied with a list of bytes, packed structs make it easier to write programs which access the contents.

    Otherwise you end up using C++ and writing a class with accessor methods and stuff that does pointer arithmetic behind the scenes. In short, packed structs are for dealing efficiently with packed data, and packed data may be what your program is given to work with. For the most part, you code should read values out of the structure, work with them, and write them back when done. All else should be done outside the packed structure. Part of the problem is the low level stuff that C tries to hide from the programmer, and the hoop jumping that is needed if such things really do matter to the programmer. (You almost need a different 'data layout' construct in the language so that you can say 'this thing is 48 bytes long, foo refers to the data 13 bytes in, and should be interpreted thus'; and a separate structured data construct, where you say 'I want a structure containing two ints, called alice and bob, and a float called carol, and I don't care how you implement it' -- in C both these use cases are shoehorned into the struct construct.)

提交回复
热议问题