Pregunta sobre bit-fields, enums, c++ – ¿Por qué la enumeración es incompatible con los campos de bits en Windows?

1

Estoy trabajando en la interfaz del protocolo EBDS para Windows y Linux. Estoy tratando de empaquetar todos los datos requeridos por el protocolo en estructuras, luego escribo la estructura en sí misma y todas las demás cosas en el puerto serial que las envía al dispositivo.

La primera parte del protocolo es el paquete de datos, y una de las partes del paquete es el byte de control que coincide con esta descripción:

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.

Para manejar este byte de control, creé dos enumeraciones y una estructura:

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

Cuando pido el tamaño de la estructura sControlByte, el valor es igual a 6 en la compilación de Windows (Visual studio 2010) pero en Linux (usando gcc 4.2.3) el tamaño de la estructura es 1, como se esperaba.

Intenté deshacerme de las alineaciones con los atributos requeridos en ambas plataformas, pero no sé qué me falta. ¿Por qué cambia el tamaño dependiendo de la plataforma? ¿Estoy usando los atributos correctos para controlar la alineación?

Gracias por adelantado.

@harper Tienes razón, lo he pasado por alto de alguna manera. Dmitry Egorenkov
El compilador VS también tiene el paquete () pragma, por lo que no es necesario si lo define. Dmitry Egorenkov
@Dmitry the ifndef LINUX permite el paquete ()solamente para MSVC, así que absolutamente lo necesitas. harper

Tu respuesta

1   la respuesta
4

El estándar C ++ no especifica cómo se distribuyen exactamente los campos de bits. Muchos compiladores usarán enteros regulares para cada componente de campo de bits, lo que significa un procesamiento más rápido pero estructuras más grandes, a menos que especifique una preferencia diferente que haya hecho en el caso de Linux.

Veraquí Para el algoritmo utiliza VS2010.

Editar: Hay un problema con tu codigo Recuerde que con un tipo de base con signo, el bit de signo consumirá un bit del campo de bits. Y sus enums (como la mayoría de las personas) pueden estar firmados (ya sea que estén, se definan como implementados) y, por lo tanto, es posible que tenga sorpresas cuando almaceneE_EXTENDED_COMMANDS enmMessageType e inmediatamente descubra queel valor no está ahí.

Con compiladores recientes, puedesforzar a los enumerados a ser sin firmar y evitar este problema.

Curioso, pensé que ya que el campo de bits está involucrado, el tipo base del campo no importa para otra cosa que el uso en el código pero no en el tamaño. PaperBirdMaster
@PaperBirdMaster - Eso es cierto. Sin embargo, el acceso a los componentes del campo de bits suele ser más rápido cuando NO están empaquetados porque, por lo tanto, no es necesario desplazar y enmascarar campos adyacentes en el nivel de generación de código. Por cierto, me acabo de dar cuenta de que su estructura puede no funcionar en absoluto en algunas plataformas, vea Editar para la respuesta. Jirka Hanika

Preguntas relacionadas