C++ struct alignment question

后端 未结 6 801
清歌不尽
清歌不尽 2020-12-05 09:12

I have a predefined struct (actually several) where variables span across 32-bit word boundary. In Linux (and Windows using GCC) I am able to get my structs to pack to the

相关标签:
6条回答
  • 2020-12-05 09:26

    Crazy idea: just write a C99 or C++03 -conforming program in the first place


    I would suggest not using vendor-specific C language extensions to match device or network bit formats. Even if you get the fields to line up using a series of one-per-vendor language extensions, you still have byte order to worry about, and you still have a struct layout that requires extra instructions to access.

    You can write a C99 conforming program that will work on any architecture or host and at maximum speed and cache efficiency by using the standardized C API string and memory copy functions and the Posix hton and ntoh functions.

    A good practice is to use the following functions for which there exist published standards:

    C99: memcpy(), Posix: htonl(), htons(), ntohl(), ntohs()
    

    Update: here is some code that should work the same everywhere. You may need to get <stdint.h> from this project if Microsoft still hasn't implemented it for C99, or just make the usual assumptions about int sizes.

    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include <arpa/inet.h>
    
    struct packed_with_bit_fields {  // ONLY FOR COMPARISON
        unsigned int   a        : 3;
        unsigned int   b        : 1;
        unsigned int   c        : 15;
        unsigned int   troubleMaker : 16;
        unsigned short padding  : 13;
    } __attribute__((packed));       // USED ONLY TO COMPARE IMPLEMENTATIONS
    
    struct unpacked { // THIS IS THE EXAMPLE STRUCT
        uint32_t a;
        uint32_t b;
        uint32_t c;
        uint32_t troubleMaker;
    }; // NOTE NOT PACKED
    
    struct unpacked su;
    struct packed_with_bit_fields sp;
    char *bits = "Lorem ipsum dolor";
    
    int main(int ac, char **av) {
      uint32_t x;   // byte order issues ignored in both cases
    
      // This should work with any environment and compiler
      memcpy(&x, bits, 4);
      su.a = x & 7;
      su.b = x >> 3 & 1;
      su.c = x >> 4 & 0x7fff;
      memcpy(&x, bits + 2, 4);
      su.troubleMaker = x >> 3 & 0xffff;
    
      // This section works only with gcc
      memcpy(&sp, bits, 6);
      printf( sp.a == su.a
          &&  sp.b == su.b
          &&  sp.c == su.c
          &&  sp.troubleMaker == su.troubleMaker
          ? "conforming and gcc implementations match\n" : "huh?\n");
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-05 09:35

    I don't believe this behavior is supported in Visual Studio. In addiction to the pack macro I tried using __declspec(align(1)) and got the same behavior. I think you are stuck with 12 bytes or re-ordering your structure a bit.

    0 讨论(0)
  • 2020-12-05 09:43

    Shorter example with only conforming code


    struct unpacked {  // apparently my other example was too long and confusing
        uint32_t a;    // ...here is a much shorter example with only the conforming
        uint32_t b;    // ...code. (The other program had the gcc-specific declaration,
        uint32_t c;    // but only for test code. Still, it was a bit long.)
        uint32_t troubleMaker;
    };
    
    struct unpacked su;
    char *bits = "Lorem ipsum dolor";
    
    void f(void) {
      uint32_t x;
    
      memcpy(&x, bits, 4);
      su.a = x & 7;
      su.b = x >> 3 & 1;
      su.c = x >> 4 & 0x7fff;
      memcpy(&x, bits + 2, 4);
      su.troubleMaker = x >> 3 & 0xffff;
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-05 09:46

    Alignment and ordering of bitfields are notoriously implementation-specific. It is much safer to declare a normal integer field and manipulate the "bitfields" within using masks and bitwise (| & ^) operators .

    0 讨论(0)
  • 2020-12-05 09:50

    I believe VC++ doesn't support this, and I have grave doubts whether GCC's behaviour in this respect is actually standard.

    0 讨论(0)
  • 2020-12-05 09:51

    If it absoloutely defnitely needs to be 6 bytes then define it as 3 shorts and get the data out yourself ... it won't slow things down ... the compiler is just doing this anyway ...

    0 讨论(0)
提交回复
热议问题