问题描述
我正在为Windows和Linux开发EBDS协议接口。我正在尝试将协议所需的所有数据打包成结构体,然后将结构本身和所有其他内容写入串口发送到设备。协议的第一部分是数据打包,程序包的其中一个部分是与该描述相符的控制字节:
位0:确认位(每次发送中0和1之间切换)。
位1到3:设备类型。
位4到6:消息类型。
位7:未使用。
为了处理tis控制字节,我创建了两个枚举和一个结构体:
枚举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,
};
枚举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
} __属性__((打包));
#else
};
#endif
当我要求sControlByte结构体的大小时,值等于6 Windows编译(Visual studio 2010),但在Linux上(使用gcc 4.2.3),结构的大小是1,如预期的那样。
我试图摆脱对齐在两个平台上都具有必需的属性,但我不知道我是什么缺陷¿为什么尺寸根据平台而有所不同? ¿我使用正确的属性来控制对齐方式?
提前感谢。
C ++标准没有指定位字段如何精确布局。许多编译器将为每个位字段组件使用常量整数,这意味着更快的处理速度,但是更大的结构体,除非您指定了在Linux下所做的不同偏好。
有关VS2010使用的算法,请参阅。
修改:您的代码有问题。记住,使用带符号的基类型,位字段的一位将被符号位消耗。您的枚举(像大多数人一样)可能被签名(不管是否是实现定义),因此当您在中存储
,并立即发现该值不在。 E_EXTENDED_COMMANDS
时,您可能会看到惊喜mMessageType
使用最近的编译器,您可以,并避免此问题。
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.
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.
这篇关于为什么枚举与Windows中的位域不兼容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!