Вопрос по c++ – Почему перечисление несовместимо с битовыми полями в Windows?

1

Я работаю над интерфейсом протокола EBDS для Windows и Linux. Я пытаюсь упаковать все данные, требуемые протоколом, в структуры, затем записываю саму структуру и все остальные данные в последовательный порт, отправляя их на устройство.

Первой частью протокола является упаковка данных, а одной из частей пакета является управляющий байт, который соответствует этому описанию:

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.

Для обработки этого управляющего байта я создал два перечисления и одну структуру:

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

Когда я запрашиваю размер структуры sControlByte, при компиляции Windows (Visual Studio 2010) значение равно 6, но в Linux (с использованием gcc 4.2.3) размер структуры равен 1, как и ожидалось.

Я пытался избавиться от выравнивания с необходимыми атрибутами на обеих платформах, но я не знаю, что мне не хватает ¿Почему размер меняется в зависимости от платформы? ¿Я использую правильные атрибуты для управления выравниванием?

Заранее спасибо

VS-компилятор также имеет прагму pack (), поэтому вам не нужно его задавать. Dmitry Egorenkov
@ Дмитрий ifndef LINUX позволяет пакет ()тольк для MSVC, так что вам это нужно. harper
@ harper Вы правы, я как-то это упустил. Dmitry Egorenkov

Ваш Ответ

1   ответ
4

как точно размечены битовые поля. Многие компиляторы будут использовать обычные целые числа для каждого компонента битового поля, что означает более быструю обработку, но более крупные структуры, если вы не укажете другое предпочтение, которое вы сделали в случае Linux.

ВидетьВо для алгоритма VS2010 использует.

Редактироват: Проблема с вашим кодом. Помните, что при знаковом базовом типе один бит битового поля будет использоваться знаковым битом. И ваши перечисления (как и большинство людей) могут быть подписаны (независимо от того, являются ли они, определяется реализацией), и, таким образом, вы можете увидеть сюрпризы при храненииE_EXTENDED_COMMANDS вmMessageType и сразу узнаешь, что ценности там нет.

С недавними компиляторами вы можете сделать перечисления неподписанными и избегай этой проблемы.

curious, я подумал, что, поскольку битовое поле задействовано, базовый тип поля не имеет значения для другой вещи - использование в коде, но не в размере. PaperBirdMaster
@ PaperBirdMaster - это правда. Однако доступ к компонентам битового поля обычно происходит быстрее, когда они НЕ упакованы, потому что тогда нет необходимости по-разному сдвигать и маскировать соседние поля на уровне генерации кода. Кстати, я только что заметил, что ваша структура может не работать вообще на некоторых платформах, см. Изменить к ответу. Jirka Hanika

Похожие вопросы