c - Size of struct with bitfields different between Linux (gcc) and Windows (mingw32 gcc) -


similar question, specific packed structs: why size of packed structure different on linux , windows when using gcc?


i'm building shared library linux , windows needs deal well-structured data on network connection. i'm using gcc 4.8.2 on linux, , cross-compiling windows targets using i686-pc-mingw32-gcc 4.8.1.

i've made little program demonstrate issue (note gcc attributes commented out, left them in reference):

#include <stdio.h> #include <stdint.h> #include <stdlib.h>  typedef uint16_t word_t;  typedef enum //__attribute__((__packed__)) {   prio_0 = 0,   prio_1,   prio_2,   prio_3,   prio_4,   prio_5,   prio_6,   prio_7, } prio_t;  typedef enum //__attribute__((__packed__)) {   flag_a = 0,   flag_b, } flag_t;  typedef struct //__attribute__((__packed__)) {   word_t id     : 8;   prio_t prio   : 3;   flag_t flag_1 : 1;   flag_t flag_2 : 1;   flag_t flag_3 : 1;   flag_t flag_4 : 1;   word_t spare  : 1; } recd_t;   int main(int argc, char *argv[]) { #define name_width 32    printf("%-*s = %lu\n", name_width, "sizeof(prio_t)", (unsigned long)sizeof(prio_t));   printf("%-*s = %lu\n", name_width, "sizeof(flag_t)", (unsigned long)sizeof(flag_t));   printf("%-*s = %lu\n", name_width, "sizeof(recd_t)", (unsigned long)sizeof(recd_t));    return 0; } 

i'm compiling linux using: gcc -g -wall test.c -o ./test

and windows: i686-pc-mingw32-gcc -g -wall test.c -o ./test.exe

very straightforward thought. when run on linux, output expect:

sizeof(prio_t)                   = 4 sizeof(flag_t)                   = 4 sizeof(recd_t)                   = 4 

but on windows:

sizeof(prio_t)                   = 4 sizeof(flag_t)                   = 4 sizeof(recd_t)                   = 12 

so what's deal windows sizes? why different linux in case?


i need pack these enums , structs, issue appears before packing done. when enabled though, results similar:

linux:

sizeof(prio_t)                   = 1 sizeof(flag_t)                   = 1 sizeof(recd_t)                   = 2 

windows:

sizeof(prio_t)                   = 1 sizeof(flag_t)                   = 1 sizeof(recd_t)                   = 6 

the c specification has informative annex (annex j) summarizes unspecified behavior, undefined behavior, , implementation defined behavior. here's says bit-fields.

j.3 implementation-defined behavior

a conforming implementation required document choice of behavior in each of areas listed in subclause. following implementation-defined:

j.3.9 structures, unions, enumerations, , bit-fields

  • whether "plain" int bit-field treated signed int bit-field or unsigned int bit-field (6.7.2, 6.7.2.1).

  • allowable bit-field types other _bool, signed int, , unsigned int (6.7.2.1).

  • whether atomic types permitted bit-fields (6.7.2.1).
  • whether bit-field can straddle storage-unit boundary (6.7.2.1).
  • the order of allocation of bit-fields within unit (6.7.2.1).
  • the alignment of non-bit-field members of structures (6.7.2.1). should present no problem unless binary data written 1 implementation read another.
  • the integer type compatible each enumerated type (6.7.2.2).

you can draw own conclusions, not use bit-fields in code that's intended portable.


it seems on windows, compiler starts new "unit" every time type changes. in unpacked case, have word_t (2 bytes) followed prio_t (4 bytes), flag_t (4 bytes), , word_t (2 bytes) total of 12 bytes. when packed it's 2,1,1,2 total of 6. if declared fields uint16_t, you'll correct size on windows, still have problem of "the order of allocation of bit-fields within unit" implementation defined.


Comments