The requests for packing request that the compiler pack the members into the structures, with no padding. However, they do not change the types or representations of the members themselves. It appears GCC and Clang use three bytes to represent a bit-field of 17 bits and Microsoft uses four, at least when the base type is uint32_t. Thus, for this structure, Clang and GCC pack a one-byte object, a four-byte object, and a three-byte object into eight bytes, while Microsoft packs a one-byte object, a four-byte object, and a four-byte object into nine bytes.
This may be related to the fact that Microsoft‘s compiler is primarily a C++ compiler and C and C++ treat the types of bit-fields differently. In C, the type of a bit-field may be implementation-defined (the standard is not entirely clear). In C++, the type of a bit-field is its base type.
We can test this by considering a rearrange unpacked structure:
struct S
{
uint8_t f0;
uint32_t f2 : 17;
uint32_t f1;
};
GCC and Clang show sizeof(struct S) to be eight bytes, which is consistent with a three-byte representation for the bit-field. MSVC shows twelve bytes, which is consistent with a four-byte representation for the bit-field.