0

我正在尝试将一个相对复杂的消息编码到一个联合结构中,以便我可以生成一个可以输入串行通信协议的 uint8_t 数组。

但是,当查看我的并集填充数据时生成的数组时,我的命令类型元素之后会出现一个额外的 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];
};

如您所见,有第二个匿名联合引用联合 myint16_t。因此,如果我填充匿名联合的所有值,然后打印出底层 data[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 并发布另一个位. 为什么会这样?

注意:您可能会看到索引上升到计数 data[53] 应该超出范围,但我需要阅读并发送它以便能够解构另一端的数据。

4

2 回答 2

0

commandtype和之间几乎肯定有一个填充字节UpperLimits;2 字节myint16_t数据类型在偶数字节边界上对齐。

struct {
    uint8_t commandtype;
    myint16_t UpperLimits[4];
    ...

如果您可以打印匿名结构和联合的大小,您可能会发现它至少有 54 个字节(您认为应该是 53 个字节)。嵌入为联合的匿名成员的未标记结构类型的缺点之一是没有简单的方法来打印结构的大小。给结构一个标签(struct tag { uint8_t commandtype; ...),以便您可以打印出它的大小。

使用当前框架并没有简单的解决方法。

于 2013-10-07T03:38:45.867 回答
0

您需要告诉编译器如何对齐联合或结构中的元素。只需在定义前添加#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);
于 2013-10-07T04:03:13.863 回答