我正在尝试将一个相对复杂的消息编码为一个联合结构,这样我就可以生成一个uint8_t数组,我可以将其输入到串行通信协议中。
但是,当查看我的union填充数据时生成的数组时,在我的命令类型元素后面会出现一个额外的uint8_t元素。请参阅下面的联盟结构:
union myint16_t{
uint16_t ui16;
int16_t i16;
uint8_t data[2];
};
union {
struct {
uint8_t commandtype;
myint16_t UpperLimits[4];
myint16_t LowerLimits[4];
myint16_t JointZeros[4];
int8_t JointPolarity[4];
myint16_t P[4];
myint16_t I[4];
myint16_t D[4];
};
uint8_t data[53];
};
你可以看到第二个匿名联盟引用了union myint16_t。 因此,如果我填充匿名联合的所有值,然后打印出基础数据[53]数组,我的第二个值(data [1])为0,而不是UpperLimits [4]的第一个元素的一部分。请参阅我填充联合的代码,然后打印出元素。
char q = 'c';
hmmv4_configmsg msg;
msg.commandtype =(uint8_t) q;
msg.UpperLimits[0].ui16 = 784;
msg.UpperLimits[1].ui16 = 784;
msg.UpperLimits[2].ui16 = 784;
msg.UpperLimits[3].ui16 = 784;
msg.LowerLimits[0].ui16 = 223;
msg.LowerLimits[1].ui16 = 223;
msg.LowerLimits[2].ui16 = 223;
msg.LowerLimits[3].ui16 = 223;
msg.JointZeros[0].ui16 = 512;
msg.JointZeros[1].ui16 = 512;
msg.JointZeros[2].ui16 = 512;
msg.JointZeros[3].ui16 = 512;
msg.JointPolarity[0] = -1;
msg.JointPolarity[1] =-1;
msg.JointPolarity[2] =-1;
msg.JointPolarity[3] =-1;
msg.P[0].i16=4000;
msg.P[1].i16=4000;
msg.P[2].i16=4000;
msg.P[3].i16=4000;
msg.I[0].i16=1;
msg.I[1].i16=1;
msg.I[2].i16=1;
msg.I[3].i16=1;
msg.D[0].i16=24;
msg.D[1].i16=24;
msg.D[2].i16=24;
msg.D[3].i16=24;
//msg.change_endian();
while(1)
{
for(int i =0; i<54; i++)
{
writebuf[i]=msg.data[i];
printf("D: %d, %d \n", i, msg.data[i]);
}
printf("L0: %d, %d, %d", msg.P[0].i16, msg.P[0].data[0], msg.P[0].data[1]);
int r =jointencoder.xfer1(writebuf, readbuf, 54);
}
printf的输出是(违规元素是D:1 - 它不应该存在):
D: 0, 99
D: 1, 0
D: 2, 16
D: 3, 3
D: 4, 16
D: 5, 3
D: 6, 16
D: 7, 3
D: 8, 16
D: 9, 3
D: 10, 223
D: 11, 0
D: 12, 223
D: 13, 0
D: 14, 223
D: 15, 0
D: 16, 223
D: 17, 0
D: 18, 0
D: 19, 2
D: 20, 0
D: 21, 2
D: 22, 0
D: 23, 2
D: 24, 0
D: 25, 2
D: 26, 255
D: 27, 255
D: 28, 255
D: 29, 255
D: 30, 160
D: 31, 15
D: 32, 160
D: 33, 15
D: 34, 160
D: 35, 15
D: 36, 160
D: 37, 15
D: 38, 1
D: 39, 0
D: 40, 1
D: 41, 0
D: 42, 1
D: 43, 0
D: 44, 1
D: 45, 0
D: 46, 24
D: 47, 0
D: 48, 24
D: 49, 0
D: 50, 24
D: 51, 0
D: 52, 24
D: 53, 0
L0: 4000, 160, 15joint encoder transferred
我的问题是为什么D:1在那里?我对联合和结构的理解是因为命令类型是uint8_t,那么它应该只占用一个数据空间,因此UpperLimits [0]应该从D:1开始,但似乎command_type充当uint16_t并发布另一个位。为什么会这样?
注意:您可能会看到索引向上计数数据[53]应该超出范围,但我需要读取并发送它以便能够在另一端解构数据。 / p>
答案 0 :(得分:0)
commandtype
和UpperLimits
之间几乎肯定存在填充字节; 2字节myint16_t
数据类型在偶数字节边界上对齐。
struct {
uint8_t commandtype;
myint16_t UpperLimits[4];
...
如果你可以打印匿名结构和联合的大小,你可能会发现它至少是54个字节(你认为它应该是53个字节)。嵌入作为联合的匿名成员的未标记结构类型的缺点之一是没有简单的方法来打印结构的大小。为结构提供一个标记(struct tag { uint8_t commandtype; ...
),以便您可以打印出它的大小。
使用当前框架没有一个简单的解决方法。
答案 1 :(得分:0)
您需要告诉编译器如何对齐union或struct中的元素。只需在定义之前添加#pragma pack(push,1),以指示编译器在单字节边界上对齐相邻元素,然后使用#pragma pack(pop)恢复到编译器的默认对齐。出于性能原因,您不希望对所有结构/联合/类使用单字节对齐,因此最好将联合定义包装在pragma对中。
示例:
#pragma pack(push,1)
union
{
uint_8 first;
uint_8 second;
} two_bytes;
#pragma pack(pop)
assert(sizeof two_bytes == 2);