最近在帮另外一个项目组做一个小小的程序。程序主要是发送一串命令数据,然后,接收一串数据。项目的难度并不大,但发现其一个技术知识点还是可以分享出来的。
//这个结构体的定义正确吗? typedef struct create_cmd_s { uint8_t action_id; uint8_t section_id; uint32_t block_id; uint32_t data[8]; }create_cmd_t;
一、字节对齐的基本概念
在我们的Cortex-M系列MCU中,我们常常使用4字节对齐。
二、C语言中结构体的字节对齐
在C语言中,结构体(struct)是一种复合数据类型,它允许将不同类型的数据组合在一起。C语言中的结构体默认会按照最大成员类型的大小进行对齐,这是为了保证访问结构体中的任何成员时都能达到最优的性能。上面的示例代码中,结构体在内存的存储形式如下图所示:
从这张内存图上可以清楚地看到,有两个字节被系统给reserved了。一方面,其带来了存储空间的损失;另一方面,对于字节流的传输数据的内容也对不上了——本来第3字节应该是block_id的数据了嘛!
三、Keil编程环境下的字节对齐
在Keil编程环境下,我们可以使用特定的编译器指令来控制结构体的字节对齐。例如,使用#pragma pack指令可以改变结构体的对齐方式。
#pragma pack(1):这条指令告诉编译器,结构体中的成员应该按照1字节对齐。这可以最大限度地节省内存空间,但可能会降低硬件访问的效率。
#pragma pack(4):这条指令告诉编译器,结构体中的成员应该按照4字节对齐。这是许多处理器默认的访问宽度,因此在这种情况下,硬件访问的效率会相对较高。
需要注意的是,使用#pragma pack#pragma pack()指令恢复默认的对齐方式,否则会影响后续代码中的其他结构体。
四、总结
字节对齐是C语言编程中一个重要的概念,特别是在嵌入式系统开发中。在Keil编程环境下,通过合理地使用#pragma pack指令,我们可以有效地控制结构体的字节对齐,从而平衡内存使用和硬件访问效率。通过深入理解和应用字节对齐,我们可以编写出更加高效和健壮的嵌入式系统代码。
最后,给出来文章开头处定义的结构体的正确源代码:
#pragma pack(1) typedef struct create_cmd_s { uint8_t action_id; uint8_t section_id; uint32_t block_id; uint32_t data[8]; }create_cmd_t; #pragma pack()