c++visual-c++structpragma-pack

C++ padding of struct still occurs when using #pragma pack


I am trying to implement a 24-bit integral datatype using a c++ struct. I want its size to be 24 bits / 3 bytes -- not padded into a 4 byte int. I am using Visual Studio Community 2019's compiler.

I have tried using #pragma pack to prevent this as shown below, but sizeof( int24 ) still returns 4.

#pragma pack(push, 1)

struct int24{
    unsigned int data : 24;
};

#pragma pack(pop)

How can I get the struct to have a size of 3 bytes? I want to avoid using an array of unsigned chars if possible.


Solution

  • According to my understanding of the #pragma pack documentation it is only related to adding padding bytes between (or after) members in a structure, and not to the size allocated for a member itself.

    In order to achieve what you want you can use a struct holding a std::array of 3 bytes, with accessors for converting a uint32_t value to/from it:

    #include <iostream>
    #include <array>
    #include <cstdint>
    
    struct int24 {
        explicit int24(uint32_t value)
        {
            set(value);
        }
    
        void set(uint32_t value)
        {
            bytes[0] = static_cast<uint8_t>(value & 0x000000ff);
            bytes[1] = static_cast<uint8_t>((value & 0x0000ff00) >> 8);
            bytes[2] = static_cast<uint8_t>((value & 0x00ff0000) >> 16);
        }
    
        uint32_t get()
        {
            uint32_t value = bytes[0] + (bytes[1] << 8) + (bytes[2] << 16);
            return value;
        }
    
    private:
        std::array<uint8_t,3> bytes;
    };
    
    int main()
    {
        std::cout << sizeof(int24) << std::endl;
        int24 i24{ 12345 };
        std::cout << i24.get();
    }
    

    Output:

    3
    12345
    

    Live demo

    Note that this solution is dependant on the Endianness of your system.