需要有关union struct的帮助。我正在接收由各种数据包组成的字节流,因此我将字节数据放入union结构并通过struct成员访问所需的数据。问题出在uint32_t类型的成员 - 读取时跳过它的两个字节,并在通过其成员访问时显示错误的值。这是完整的演示代码:
PacketUtils.h
#include <stdint.h>
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint32_t deviceId;
uint16_t packetCRC;
} PacketData;
typedef union {
uint8_t *bytes; // stores raw bytes
PacketData *packet;
} Packet;
// Puts bytes into predefined struct
void getPacketFromBytes(void *bytes, Packet *packetRef);
PacketUtils.c
#include <stdio.h>
#include "UnionStruct.h"
void getPacketFromBytes(void *bytes, Packet *packetRef)
{
uint8_t *rawBytes = (uint8_t *)bytes;
packetRef->bytes = rawBytes;
}
致电代码:
// sample byte data
uint8_t packetBytes[] = {0x11, 0x02, 0x01, 0x01, 0x01, 0x03, 0xbb, 0xbd};
Packet packetRef;
getPacketFromBytes(packetBytes, &packetRef);
printf("%x\n", packetRef.packet->startSymbol); // good - prints 0x11
printf("%x\n", packetRef.packet->packetType); // good - prints 0x02
printf("%x\n", packetRef.packet->deviceId); // bad - prints bd bb 03 01
printf("%x\n", packetRef.packet->packetCRC); // bad - prints 36 80 (some next values in memory)
当PacketData结构由uint8_t或uint16_t类型成员组成时,一切正常,然后打印显示正确的值。但是,打印类型为uint32_t的deviceId会跳过两个字节(0x01 0x01)并占用最后4个字节。打印packetCRC打印出给定字节数组的值 - 内存中的两个值,如packetBytes [12]和packetBytes [13]。我无法弄清楚为什么它会跳过两个字节...
答案 0 :(得分:1)
32位数字仅在4字节边界上对齐。如果将它移动到结构的开头,它可能只是按你的意愿工作。
处理器通常经过优化,可以在数据大小的倍数上获取数据 - 32位为4个字节,64位为8个字节... - 编译器知道这一点并在数据结构中添加间隙以确保处理器可以有效地获取数据。
如果您不想处理填充并且无法移动数据结构,则可以定义
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint16_t deviceIdLow;
uint16_t deviceIdHigh;
uint16_t packetCRC;
} PacketData;
然后写下
uint32_t deviceID = packetRef.packet->deviceIdLow | (packetRef.packet->deviceIdLow << 16);
答案 1 :(得分:1)
问题是由于您的平台上的字段被填充到默认对齐方式。在大多数现代架构中,32位值在读取/写入32位字对齐地址时效率最高。
在gcc中,您可以通过使用特殊属性来指示结构是“已打包”来避免这种情况。见这里:
http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Type-Attributes.html
所以struct定义看起来像这样:
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint32_t deviceId;
uint16_t packetCRC;
} PacketData __attribute__((packed));