gpt4 book ai didi

c - 初始化、构造结构并将其转换为字节数组会导致未对齐

转载 作者:行者123 更新时间:2023-11-30 15:19:12 25 4
gpt4 key购买 nike

我正在尝试设计一个用于字节级通信的数据结构(我已将其缩短以节省空间,但我认为您已经明白了):

/* PACKET.H */    
#define CM_HEADER_SIZE 3
#define CM_DATA_SIZE 16
#define CM_FOOTER_SIZE 3
#define CM_PACKET_SIZE (CM_HEADER_SIZE + CM_DATA_SIZE + CM_FOOTER_SIZE)
// + some other definitions

typedef struct cm_header{
uint8_t PacketStart; //Start Indicator 0x5B [
uint8_t DeviceId; //ID Of the device which is sending
uint8_t PacketType;
} CM_Header;

typedef struct cm_footer {
uint16_t DataCrc; //CRC of the 'Data' part of CM_Packet
uint8_t PacketEnd; //should be 0X5D or ]
} CM_Footer;

//Here I am trying to conver a few u8[4] tp u32 (4*u32 = 16 byte, hence data size)
typedef struct cm_data {
union {
struct{
uint8_t Value_0_0:2;
uint8_t Value_0_1:2;
uint8_t Value_0_2:2;
uint8_t Value_0_3:2;
};
uint32_t Value_0;
};
//same thing for Value_1, 2 and 3
} CM_Data;

typedef struct cm_packet {
CM_Header Header;
CM_Data Data;
CM_Footer Footer;
} CM_Packet;

typedef struct cm_inittypedef{
uint8_t DeviceId;
CM_Packet Packet;
} CM_InitTypeDef;

typedef struct cm_appendresult{
uint8_t Result;
uint8_t Reason;
} CM_AppendResult;

extern CM_InitTypeDef cmHandler;

这里的目标是建立通过 USB 接口(interface)传输数据的可靠结构。最后,CM_Packet 应转换为 uint8_t 数组,并提供给 MCU(stm32)的数据发送寄存器。

main.c 文件中,我尝试初始化结构以及与此数据包相关的其他一些内容:

/* MAIN.C */
uint8_t packet[CM_PACKET_SIZE];
int main(void) {
//use the extern defined in packet.h to init the struct
cmHandler.DeviceId = 0x01; //assign device id
CM_Init(&cmHandler); //construct the handler
//rest of stuff

while(1) {
CM_GetPacket(&cmHandler, (uint8_t*)packet);
CDC_Transmit_FS(&packet, CM_PACKET_SIZE);
}
}

这是 packet.h 的实现,它把一切搞砸了。我添加了要观看的数据包[CM_PACKET_SIZE],但它就像是随机生成的。有时,纯粹是运气好,我可以在这个数组中看到一些我感兴趣的值!但大约只有 1% 的时间!

/* PACKET.C */
CM_InitTypeDef cmHandler;

void CM_Init(CM_InitTypeDef *cm_initer) {
cmHandler.DeviceId = cm_initer->DeviceId;

static CM_Packet cmPacket;
cmPacket.Header.DeviceId = cm_initer->DeviceId;
cmPacket.Header.PacketStart = CM_START;
cmPacket.Footer.PacketEnd = CM_END;
cm_initer->Packet = cmPacket;
}

CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier,
uint8_t *data){

CM_AppendResult result;

switch(identifier){
case CM_VALUE_0:
handler->Packet.Data.Value_0_0 = data[0];
handler->Packet.Data.Value_0_1 = data[1];
handler->Packet.Data.Value_0_2 = data[2];
handler->Packet.Data.Value_0_3 = data[3];
break;

//Also cases for CM_VALUE_0, 1 , 2
//to build up the CM_Data sturct of CM_Packet

default:
result.Result = CM_APPEND_FAILURE;
result.Reason = CM_APPEND_CASE_ERROR;
return result;
break;

}

result.Result = CM_APPEND_SUCCESS;
result.Reason = 0x00;
return result;
}

void CM_GetPacket(CM_InitTypeDef *handler, uint8_t *packet){
//copy the whole struct in the given buffer and later send it to USB host
memcpy(packet, &handler->Packet, sizeof(CM_PACKET_SIZE));
}

所以,问题是这段代码 99% 的时间都会给我随机的东西。它从来没有 CM_START 这是数据包的开始指示符到我想要的值。但大多数时候它都正确地具有 CM_END 字节!我真的很困惑,找不到原因。在一个很难调试的嵌入式平台上工作,我有点迷失在这里......

最佳答案

如果将数据传输到另一个(不同的)体系结构,请勿仅将结构作为 blob 传递。这就是通往 hell 的道路:字节顺序、对齐方式、填充字节等都可能(并且可能会)造成麻烦。

更好地以一致的方式序列化结构,可能使用一些解释的控制流,这样您就不必手动写出每个字段。 (但仍然使用标准函数来生成该流)。

一些潜在或可能出现问题的领域:

  • CM_Footer:第二个字段很可能从 32 或 64 位边界开始,因此前一个字段后面将进行填充。此外,在 32 位体系结构上,该结构的末尾很可能会填充至少 1 个字节,以便在数组中使用时进行正确对齐(如果您确实需要这样做,编译器不会关心您)。它甚至可能是 8 字节对齐的。
  • CM_Header:在这里您可能(不保证)得到一个 4*2 位的 uint8_t,且排序未标准化。该字段后面可能跟随 3 个未使用的字节,这是 union 的 uint32_t 解释所必需的。
  • 如何保证主机和目标具有相同的字节顺序(对于 >uint8_t:高字节优先还是低字节优先?)?
  • 一般来说,结构体/union 体的主机和目标不需要具有相同的布局。即使使用相同的编译器,它们的ABI也可能不同等。即使是相同的CPU,也可能存在其他系统限制。此外,对于某些 CPU,存在不同的 ABI(应用程序二进制接口(interface))。

关于c - 初始化、构造结构并将其转换为字节数组会导致未对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30820038/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com