内部FLASH存储器中C结构的对齐

发布于 2024-12-21 11:05:04 字数 571 浏览 4 评论 0原文

我有一个配置结构,想保存在 ARM cortex M3 的内部闪存上。 根据规范,保存在内部Flash中的数据必须对齐到32bit。 因为我的结构中有很多布尔值和字符,我不想使用 32 位来存储 8 位...我决定使用 __packed 预处理器编译指示来打包结构,然后当我将其保存为整个结构,我只需确保结构大小可以被 4 整除(4 字节 = 32 位),如果需要,我可以通过添加填充字节来实现。 目前,在开发过程中我对结构进行了很多修改,为了使其与 32 位对齐,我需要一直更改填充字节。 目前,结构看起来像这样

typedef __packed struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...] // this has to be changed every time I alter the structure.
} CONFIG;

有没有更好的方法来实现我正在做的事情? 我是嵌入式编程的新手,我想确保我没有犯错误。

编辑:请注意。数据保留在内部闪存的末尾,因此省略填充将不起作用......

I have a configuration structure I would like to save on the internal flash of ARM cortex M3.
According to the specifications, the data save in the internal flash, must be aligned to 32bit.
Because I have lot's of boolean, and chars in my structure,I don't want to use 32bits to store 8 bits... I decided to pack the structure using the __packed preprocessor pragma, Then When I save it as a whole structure, I just have to make sure that the structure size is divisible by 4 (4 bytes = 32bits), I do it by adding padding bytes if needed.
Currently, during development I alter the structure a lot, and to make it aligned with the 32 bits, I need to change the padding bytes all the time.
Currently, the structure look slike this

typedef __packed struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...] // this has to be changed every time I alter the structure.
} CONFIG;

Is there a better way to achieve what I'm doing ?
I'm quite new in Embedded programming, and I want to make sure that I'm not doing mistakes.

Edit: Please note. The data is persisted in the end of the internal-flash, so omitting the padding will not work...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

狼亦尘 2024-12-28 11:05:04

首先,通常要避免压缩对齐,如果最终得到的数据未与其自然边界对齐,则当您尝试访问它们时,某些 CPU 只会发出陷阱。

首先,按顺序存储成员,以便编译器不会添加对齐间隙(或者如果添加,则会将其添加到末尾)。如果可以的话,让 1. 成员具有您想要的对齐要求 - 因为这会迫使编译器至少给予结构足够的对齐。

这需要一些关于平台和编译器的对齐要求的知识,例如摆脱填充数组,并更改

typedef struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...];
} CONFIG;

typedef struct
{
uint32_t blabla;
uint16_t delay;
uint8_t status;
uint8_t foo[5];
} CONFIG;

然后告诉编译器该结构需要 4 字节对齐(在这种情况下,它可能已经需要,因为第一个成员已经4 字节或更多对齐要求)。例如,使用 gcc 使用 attribute((__aligned__(4))

然后编写一个小测试程序来验证您的对齐要求(这只是一个在您的struct),这甚至会告诉您是否需要添加要对齐的结构的指令作为构建/打包的一部分运行该程序。

Firstly, packed alignment is usually to be avoided, if you end up with data not aligned to their natural boundaries, some CPUs will just issue a trap when you try to access them.

First, store the members in an order so the compiler doesn't add gaps for alignment (or if it does, it adds it at the end). If you can, have the 1. member have the alignment requirement you desire - as that forces the compiler to at least give the struct that much alignment.

This requires some knowledge on how the alignment requirements of your platform and compiler, e.g. get rid of the padding array, and change

typedef struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...];
} CONFIG;

to

typedef struct
{
uint32_t blabla;
uint16_t delay;
uint8_t status;
uint8_t foo[5];
} CONFIG;

Then tell the compiler that this struct needs 4 byte aligment (in this case it likely already will as the first member has 4 byte or more alignment requirement). e.g. with gcc use attribute((__aligned__(4))

Then write a small test program that validates the alignment requirements you have (which is just a small program that uses sizeof() and alignof() on your struct), this'll even tell you if you need to add instruction for the struct to be aligned. Run that program as part of the build/packaging.

遗失的美好 2024-12-28 11:05:04

也许这是一个想法:

typedef __packed struct {
    uint8_t status;
    uint16_t delay;
    uint32_t blabla;
    uint8_t foo[5];
} CONFIG;

typedef __packed struct {
    CONFIG cfg;
    uint8_t padding[4 - (sizeof(CONFIG) % 4)]
} CONFIGWRAPPER;

Perhaps this is an idea:

typedef __packed struct {
    uint8_t status;
    uint16_t delay;
    uint32_t blabla;
    uint8_t foo[5];
} CONFIG;

typedef __packed struct {
    CONFIG cfg;
    uint8_t padding[4 - (sizeof(CONFIG) % 4)]
} CONFIGWRAPPER;
情深已缘浅 2024-12-28 11:05:04

解决方案 1:您可以将其放入包含结构和字符数组的联合中:

union
{
  CONFIG config;
  uint8_t total_size[32];
} my_union;

Solution 1: You could put it inside a union containing your structure and an array of characters:

union
{
  CONFIG config;
  uint8_t total_size[32];
} my_union;
初见终念 2024-12-28 11:05:04

解决方案 2:您可以使用 IAR 特定的功能 #pragma location 将配置数据放置在特定位置,例如从闪存末尾开始的 32。这样你就不需要以任何方式填充结构:

/* Fictitious end of flash location. */ 
#pragma location=0x1234FFE0
struct [... your struct goes here ...]

Solution 2: You could use the IAR-specific feature #pragma location to place the config data at a specific location, like 32 from the end of the flash. That way you would not need to pad the structure in any way:

/* Fictitious end of flash location. */ 
#pragma location=0x1234FFE0
struct [... your struct goes here ...]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文