一、引言
曾经刚入门嵌入式在开发一个应用时,用到了自定义结构体,底层嵌入式单片机运行该结构体没问题,但是在Qt开发应用软件对接协议时,一直通不过,仔细分析才发现是QT这边的结构体字节并没有按照单字节对齐,后来在定义结构体时,增加了宏定义,强迫该结构体按照单字节对齐的方式进行编译,即可解决问题。
二、问题描述
假设有一个结构体,包含5字节头,一个字长度的负载,和一个字节的尾,例如:
typedef struct
{char head[5];unsigned short value;char endFlag;
}CMD_TypeDef;CMD_TypeDef TCMD;
很明显,这个结构体的字节大小为5+2+1=8字节,但是用sizeof对各个域进行测试,发现总共的字节数并不是8,测试代码如下:
qDebug()<<"size"<<QString::number(sizeof(TCMD.head));
qDebug()<<"size"<<QString::number(sizeof(TCMD.value));
qDebug()<<"size"<<QString::number(sizeof(TCMD.endFlag));
qDebug()<<"size"<<QString::number(sizeof(TCMD));
打印结果为:
size "5"
size "2"
size "1"
size "10"
进一步地,对这个结构体进行赋值,用并串口发出去该结构体的具体数据:
TCMD={{'A','T','+','D','='},10,0x0A};
port->write(( char*) &TCMD,sizeof(TCMD));
串口收到的数据为:41 54 2B 44 3D 1A 0A 00 0A 00
明显看到数据多了1A 和 00.
三、问题分析
从上面的串口收到结果来看,TCMD第一个成员head 变成了6字节【41 54 2B 44 3D 1A】,TCMD的成员endflag变成了2字节【0A 00】,结构体TCMD成员占用的内存分别是 6+2+2=10字节。
QT中定义的结构体在对成员进行内存分配时,往往按照“N”字节对齐的方式,即所有内容按照N字节的方式进行占用内存,如果剩余的内容占不满N字节,则N字节剩下的字节仍然给该结构成员,新的成员重新从下一个N字节进行对齐。
以上面的例子来说,显然N=2,即机构体按照2字节进行对齐,TCMD的头部head占5字节,需要占用3个N=6字节,负载value等于2字节,刚好占用一个N,而尾部endflag占用1字节,不足N,仍然需要占用一个N。
四、解决方法
既然QT编译系统对结构体按照N字节对齐,那么能否根据需要指定对齐的N数呢,其实C语言提供了这种操作,采用宏定义:
#pragram pack(N)
......//结构体定义内容
#pragram pack()
即可指定该定义的结构体内存对齐方式。
具体地,上述问题可以这样解决:
#pragram pack(1)
typedef struct
{char head[5];unsigned short value;char endFlag;
}CMD_TypeDef;
#pragram pack()CMD_TypeDef TCMD;
结构体定义的时候加上:#pragma pack(1)
定义结束部分结尾 #pragma pack()即可。