PaperBirdMaster
PaperBirdMaster

Reputation: 13320

Why is the enum incompatible with bit fields in Windows?

I'm working on EBDS protocol interface for Windows and Linux. I'm trying to pack all the data required by the protocol into structs, then I write the struct itself and all the other stuff into the serial port sending it to the device.

First part of the protocol is the data packaging, and one of the parts of the package is the Control Byte that matchs this description:

Bit 0: Acknowledgement bit (switchs between 0 and 1 in each send).
Bit 1 to 3: Device Type.
Bit 4 to 6: Message Type.
Bit 7: Unused.

To handle tis control byte i created two enums and one struct:

enum E_DEVICE_TYPE
{
    E_BILL_ACCEPTOR_WITH_SINGLE_ESCROW = 0x0, // 000
    E_RESERVED_1 = 0x1, // 001
    E_RESERVED_2 = 0x2, // 010
    E_RESERVED_3 = 0x3, // 011
    E_RESERVED_4 = 0x4, // 100
    E_RESERVED_5 = 0x5, // 101
    E_RESERVED_6 = 0x6, // 110
    E_RESERVED_7 = 0x7,
};

enum E_MESSAGE_TYPE
{
    E_RESERVED = 0x0,
    E_STANDARD_OMNIBUS_COMMAND = 0x1,
    E_NOT_USED = 0x2,
    E_OMNIBUS_WITH_BOOKMARK_MODE = 0x3,
    E_CALIBRATE_REQUEST = 0x4,
    E_FIRMWARE_DOWNLOAD_REQUEST = 0x5,
    E_AUXILIARY_COMMAND_REQUEST = 0x6,
    E_EXTENDED_COMMANDS = 0x7,
};

#ifndef LINUX
#pragma pack(1)
#endif
struct sControlByte
{
    sControlByte(bool aAcknowledgeFlag, E_DEVICE_TYPE aDeviceType, E_MESSAGE_TYPE aMessageType);

    const bool mACK : 1;
    const E_DEVICE_TYPE mDevice : 3;
    const E_MESSAGE_TYPE mMessageType : 3;
    const bool mUnused : 1;
#ifdef LINUX
}__attribute__((packed));
#else
};
#endif

When I ask for the size of sControlByte struct the value equals to 6 on Windows compilation (Visual studio 2010) but on Linux (using gcc 4.2.3) the size of the struct is 1, as expected.

I tried to get rid of alignments with the required attributes on both platforms but I don't know what I'm missing ¿Why is the size changing depending on the platform? ¿I'm using the correct attributes to control the alignment?

Thanks in advance.

Upvotes: 1

Views: 1433

Answers (1)

Jirka Hanika
Jirka Hanika

Reputation: 13529

C++ standard does not specify how bit fields are exactly laid out. Many compilers will use regular integers for each bit field components, which means faster processing but larger structs, unless you specify a different preference which you have done in case of Linux.

See here for the algorithm VS2010 uses.

Edit: There is a problem with your code. Remember that with a signed base type, one bit of the bit field will be consumed by the sign bit. And your enums (like most people's) may be signed (whether they are, is implementation defined) and thus you may see surprises when you store E_EXTENDED_COMMANDS in mMessageType and immediately find out that the value is not there.

With recent compilers, you can force the enums to be unsigned and avoid this problem.

Upvotes: 4

Related Questions