Code Yarns ‍👨‍💻
Tech BlogPersonal Blog

Size of bit fields

📅 2020-Aug-06 ⬩ ✍️ Ashwin Nanjappa ⬩ 🏷️ cpp ⬩ 📚 Archive

Bit fields can be used in structures and classes to have members whose size is limited to a certain number of bits. The size of the structure having bit fields can wildly vary between compilers. The worst case is the VC++ compiler, that can generate bit field structures that are huge compared to the GCC or clang ones.

The behavior of VC++ is quite ironic, when you consider that a big reason for using bit fields is to save space, using precisely how much you need. Just how much bigger are the VC++ bit field structures? Here is an example:

enum class CarType : uint8_t
{
    Sedan,
    SUV,
};

class CarParams
{
public:
    CarType c : 8;
    uint32_t v : 24;
};

// Size of CarParams on different compilers:
// x86-64 gcc 10.2: 4 bytes
// x64 msvc 19.24: 8 bytes

In this example, the developer probably wrote their code to exactly fit the information required for CarParams into 32 bits. They compile their code on GCC and it is indeed 4 bytes. When they compile their code for Windows, the size of their objects doubles to 8 bytes!

Suppose we want our CarParams to be as compact as possible (4 bytes) and be that size on all platforms, how can we achieve that? One possible solution is to use the pack pragma. These pragma directives seem to be supported by both gcc and VC++. They request the compiler to pack the members of the structure to a byte-alignment boundary of the value specified in the pragma. The possible values that can be used are power-of-two like: 1, 2, 4 and 8.

I found that using the pack pragma did help reduce the size of the structure on VC++ to 5 bytes. But I could not find a way to reduce to 4 bytes.

#pragma pack(1)
class CarParams
{
public:
    CarType c : 8;
    uint32_t v : 24;
};

// Size of CarParams on different compilers:
// x86-64 gcc 10.2: 4 bytes
// x64 msvc 19.24: 5 bytes