我已经在GCC中使用packed属性创建并编译了以下代码,它按预期方式工作。但是在Visual Studio中,结果与GCC不同。
#pragma pack(push, 1)
typedef struct
{
uint8_t TargetID: 6;
enum_OPCode OPCode: 3;
uint8_t CRC7: 7;
} struct_commDataPack_request;
#pragma pack(pop)
如您所见,所有元素的大小必须为16bits = 2Bytes,这在GCC中是正确的,但是在Visual Studio中,它将返回3Bytes!如果我将其大小减小到15bits,它将返回2Bytes。
我该如何解决?
答案 0 :(得分:3)
好吧,打包太依赖平台,以致于不能真正依赖它。
在VS中,当您执行“ pack(push,1)”时,实际上将填充设置为8位,并且如您所见,最终以3个字节结尾(其中6位为填充)。
但是,在GCC上的填充(如果您使用__attribute __((packed))或它的某些别名来填充)可以完全关闭。这就是为什么您只看到2个字节的原因。
为使其易于移植,为什么不编写自己的小型序列化例程?像这样:
struct_commDataPack_request s;
short wire = s.TargetID | (s.OPCode<<6) | (s.CRC7 << 9);
答案 1 :(得分:2)
我使用以下代码在VS2017中重现了
#include <stdio.h>
#include <stdint.h>
typedef enum { A,B,C } enum_OPCode;
#pragma pack(push, 1)
typedef struct
{
uint8_t TargetID : 6;
uint8_t OPCode : 3;
uint8_t CRC7 : 7;
} struct_commDataPack_request;
#pragma pack(pop)
int main()
{
printf("%zd\n", sizeof(struct_commDataPack_request));
}
这里的大小是3。
但是当我改变
uint8_t OPCode : 3;
uint8_t CRC7 : 7;
到
uint8_t OPCode : 2;
uint8_t CRC7 : 8;
(总大小仍为16位),大小为2。
如前所述,最好是编写自己的序列化/反序列化。
答案 2 :(得分:2)
如MS document中所述:
位字段的基础类型必须是整数类型。 如果位字段溢出声明类型的边界(在您的情况下为uint8_t),则会分配新的存储单元。
解决问题的一种方法是使用具有更大边界(uint16_t)的声明类型。
这是我使用的代码:
#include "pch.h"
#include <stdio.h>
#include <stdint.h>
typedef enum { A, B, C } enum_OPCode;
#pragma pack(push, 1)
typedef struct
{
uint16_t TargetID : 6;
uint16_t OPCode : 3;
uint16_t CRC7 : 7;
} struct_commDataPack_request;
#pragma pack(pop)
int main()
{
struct_commDataPack_request packet;
packet.TargetID = 0;
packet.OPCode = 7;
packet.CRC7 = 0;
unsigned char * pData = (unsigned char *)&packet;
printf("Packet size : %zd\n", sizeof(struct_commDataPack_request));
for (int i = 0; i < sizeof(packet); i++) {
printf("byte %d is [%02X]\n", i, pData[i] );
}
}
结果:
Packet size : 2
byte 0 is [C0]
byte 1 is [01]
(0x01C0位:0000 0001 1100 0000)