如何将结构数组初始化为非零值,如 0xFF?
How to initialize an array of structs to a value other than zero like 0xFF?
我有一个结构数组,需要在编译时初始化(无内存集) 为 0xFF。该数组将作为程序的一部分写入已擦除闪存。通过将其设置为 0xFF,它将在编程后保持擦除状态,应用程序可以将其用作持久存储。我找到了两种方法,一种是丑陋的,一种是解决方法。我想知道是否还有另一种语法方法我还没有找到。丑陋的方法是使用嵌套的初始化程序设置结构的每个字段。但是,它容易出错并且有点难看。我的解决方法是将结构分配为字节数组,然后使用结构类型的指针来访问数据。线性字节数组更容易初始化为非零值。
为了帮助其他人做同样的事情,我包括了使用的 gcc 属性和链接描述文件部分。
示例结构:
struct BlData_t {
uint8_t version[3];
uint8_t reserved;
uint8_t markers[128];
struct AppData_t {
uint8_t version[3];
uint8_t reserved;
uint32_t crc;
} appInfo[512] __attribute__(( packed ));
} __attribute__(( packed ));
使用我知道的最佳方式初始化为 0xFF:
// Allocate the space as an array of bytes
// because it's a simpler syntax to
// initialize to 0xFF.
__attribute__(( section(".bootloader_data") ))
uint8_t bootloaderDataArray[sizeof(struct BlData_t)] = {
[0 ... sizeof(struct BlData_t) - 1] = 0xFF
};
// Use a correctly typed pointer set to the
// array of bytes for actual usage
struct BlData_t *bootloaderData = (struct BlData_t *)&bootloaderDataArray;
不需要初始化,因为 (NOLOAD)
:
__attribute__(( section(".bootloader_data") ))
volatile const struct BLData_t bootloader_data;
添加链接描述文件:
.bootloader_data (NOLOAD):
{
FILL(0xFF); /* Doesn't matter because (NOLOAD) */
. = ALIGN(512); /* start on a 512B page boundary */
__bootloader_data_start = .;
KEEP (*(.bootloader_data)) /* .bootloader_data sections */
KEEP (*(.bootloader_data*)) /* .bootloader_data* sections */
. = ALIGN(512); /* end on a 512B boundary to support
runtime erasure, if possible */
__bootloader_data_end = .;
__bootloader_data_size = ABSOLUTE(. - __bootloader_data_start);
} >FLASH
如何在代码中使用起始地址、结束地址和大小:
extern uint32_t __bootloader_data_start;
extern uint32_t __bootloader_data_end;
extern uint32_t __bootloader_data_size;
uint32_t _bootloader_data_start = (uint32_t)&__bootloader_data_start;
uint32_t _bootloader_data_end = (uint32_t)&__bootloader_data_end;
uint32_t _bootloader_data_size = (uint32_t)&__bootloader_data_size;
更新:
- 原来我问错了问题。我不知道
(NOLOAD)
链接器部分属性告诉程序加载器不要将此部分刻录到闪存中。我接受这个答案是为了帮助其他人意识到我的错误,也可能是他们的错误。通过甚至不对该部分进行编程,我根本不必担心初始化。
- 我对
union
的答案投了赞成票,因为它们似乎是我所问问题的一个很好的解决方案。
我会使用你的结构的 union
和一个正确大小的数组,然后初始化数组成员。
union {
struct BlData_t data;
uint8_t bytes[sizeof(struct BlData_t)];
} data_with_ff = {
.bytes = {
[0 ... sizeof(struct BlData_t) - 1] = 0xff
}
};
然后您可以将您的结构作为 data_with_ff.data
访问,如果您愿意,可以定义一个指针或宏以方便使用。
(读者应该注意,指定初始化程序中的 ...
是 a GCC extension; since the question was already using this feature and is tagged gcc 我认为这里没问题。如果使用没有它的编译器,我不知道另一个.bytes = { 0xff, 0xff, 0xff ... }
之外的选项具有 0xff
的实际正确数量;您可能希望使用脚本生成它。)
明智的做法是在链接描述文件中找到命令,告诉它首先不要接触该内存。因为你为什么要擦除它只是为了再次填充 0xFF?那只会白白造成不必要的闪光磨损。
大致如下:
.bootloader_data (NOLOAD) :
{
. = ALIGN(512);
*(.bootloader_data *)
} >FLASH
如果您确实需要在纯标准 C 中进行此初始化,那么您可以将内部结构包装在匿名联合 (C11) 中,然后使用宏技巧初始化该结构:
struct BlData_t {
uint8_t version[3];
uint8_t reserved;
uint8_t markers[128];
union {
struct AppData_t {
uint8_t version[3];
uint8_t reserved;
uint32_t crc;
} appInfo[512];
uint8_t raw [512];
};
};
#define INIT_VAL 0xFF, // note the comma
#define INIT_1 INIT_VAL
#define INIT_2 INIT_1 INIT_1
#define INIT_5 INIT_2 INIT_2 INIT_1
#define INIT_10 INIT_5 INIT_5
/* ... you get the idea */
#define INIT_512 INIT_500 INIT_10 INIT_2
const struct BlData_t bld = { .raw = {INIT_512} };
此方法也可以应用于整个结构,例如,如果您想要初始化一个结构数组,并将所有项目设置为 compile-time 处的相同值。
我有一个结构数组,需要在编译时初始化(无内存集) 为 0xFF。该数组将作为程序的一部分写入已擦除闪存。通过将其设置为 0xFF,它将在编程后保持擦除状态,应用程序可以将其用作持久存储。我找到了两种方法,一种是丑陋的,一种是解决方法。我想知道是否还有另一种语法方法我还没有找到。丑陋的方法是使用嵌套的初始化程序设置结构的每个字段。但是,它容易出错并且有点难看。我的解决方法是将结构分配为字节数组,然后使用结构类型的指针来访问数据。线性字节数组更容易初始化为非零值。
为了帮助其他人做同样的事情,我包括了使用的 gcc 属性和链接描述文件部分。
示例结构:
struct BlData_t {
uint8_t version[3];
uint8_t reserved;
uint8_t markers[128];
struct AppData_t {
uint8_t version[3];
uint8_t reserved;
uint32_t crc;
} appInfo[512] __attribute__(( packed ));
} __attribute__(( packed ));
使用我知道的最佳方式初始化为 0xFF:
// Allocate the space as an array of bytes
// because it's a simpler syntax to
// initialize to 0xFF.
__attribute__(( section(".bootloader_data") ))
uint8_t bootloaderDataArray[sizeof(struct BlData_t)] = {
[0 ... sizeof(struct BlData_t) - 1] = 0xFF
};
// Use a correctly typed pointer set to the
// array of bytes for actual usage
struct BlData_t *bootloaderData = (struct BlData_t *)&bootloaderDataArray;
不需要初始化,因为 (NOLOAD)
:
__attribute__(( section(".bootloader_data") ))
volatile const struct BLData_t bootloader_data;
添加链接描述文件:
.bootloader_data (NOLOAD):
{
FILL(0xFF); /* Doesn't matter because (NOLOAD) */
. = ALIGN(512); /* start on a 512B page boundary */
__bootloader_data_start = .;
KEEP (*(.bootloader_data)) /* .bootloader_data sections */
KEEP (*(.bootloader_data*)) /* .bootloader_data* sections */
. = ALIGN(512); /* end on a 512B boundary to support
runtime erasure, if possible */
__bootloader_data_end = .;
__bootloader_data_size = ABSOLUTE(. - __bootloader_data_start);
} >FLASH
如何在代码中使用起始地址、结束地址和大小:
extern uint32_t __bootloader_data_start;
extern uint32_t __bootloader_data_end;
extern uint32_t __bootloader_data_size;
uint32_t _bootloader_data_start = (uint32_t)&__bootloader_data_start;
uint32_t _bootloader_data_end = (uint32_t)&__bootloader_data_end;
uint32_t _bootloader_data_size = (uint32_t)&__bootloader_data_size;
更新:
- 原来我问错了问题。我不知道
(NOLOAD)
链接器部分属性告诉程序加载器不要将此部分刻录到闪存中。我接受这个答案是为了帮助其他人意识到我的错误,也可能是他们的错误。通过甚至不对该部分进行编程,我根本不必担心初始化。 - 我对
union
的答案投了赞成票,因为它们似乎是我所问问题的一个很好的解决方案。
我会使用你的结构的 union
和一个正确大小的数组,然后初始化数组成员。
union {
struct BlData_t data;
uint8_t bytes[sizeof(struct BlData_t)];
} data_with_ff = {
.bytes = {
[0 ... sizeof(struct BlData_t) - 1] = 0xff
}
};
然后您可以将您的结构作为 data_with_ff.data
访问,如果您愿意,可以定义一个指针或宏以方便使用。
(读者应该注意,指定初始化程序中的 ...
是 a GCC extension; since the question was already using this feature and is tagged gcc 我认为这里没问题。如果使用没有它的编译器,我不知道另一个.bytes = { 0xff, 0xff, 0xff ... }
之外的选项具有 0xff
的实际正确数量;您可能希望使用脚本生成它。)
明智的做法是在链接描述文件中找到命令,告诉它首先不要接触该内存。因为你为什么要擦除它只是为了再次填充 0xFF?那只会白白造成不必要的闪光磨损。
大致如下:
.bootloader_data (NOLOAD) :
{
. = ALIGN(512);
*(.bootloader_data *)
} >FLASH
如果您确实需要在纯标准 C 中进行此初始化,那么您可以将内部结构包装在匿名联合 (C11) 中,然后使用宏技巧初始化该结构:
struct BlData_t {
uint8_t version[3];
uint8_t reserved;
uint8_t markers[128];
union {
struct AppData_t {
uint8_t version[3];
uint8_t reserved;
uint32_t crc;
} appInfo[512];
uint8_t raw [512];
};
};
#define INIT_VAL 0xFF, // note the comma
#define INIT_1 INIT_VAL
#define INIT_2 INIT_1 INIT_1
#define INIT_5 INIT_2 INIT_2 INIT_1
#define INIT_10 INIT_5 INIT_5
/* ... you get the idea */
#define INIT_512 INIT_500 INIT_10 INIT_2
const struct BlData_t bld = { .raw = {INIT_512} };
此方法也可以应用于整个结构,例如,如果您想要初始化一个结构数组,并将所有项目设置为 compile-time 处的相同值。