Home > database >  How to initialize an array of structs to a value other than zero like 0xFF?
How to initialize an array of structs to a value other than zero like 0xFF?

Time:04-06

I have an array of structs that I need to initialize at compile-time (no memset) to 0xFF. This array will be written as part of the program over erased flash. By setting it to 0xFF, it will remain erased after programming, and the app can use it as persistent storage. I've found two ways to do it, one ugly and one a workaround. I'm wondering if there's another way with syntax I haven't found yet. The ugly way is to use a nested initializer setting every field of the struct. However, it's error prone and a little ugly. My workaround is to allocate the struct as an array of bytes and then use a struct-typed pointer to access the data. Linear arrays of bytes are much easier to initialize to a non-zero value.

To aid anyone else doing the same thing, I'm including the gcc attributes used and the linker script portion.

Example struct:

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 ));

Initialize to 0xFF using the best way I know:

// 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;

Addition to linker script:

  .bootloader_data :
  {
    FILL(0xFF);
    . = ALIGN(512);  /* start on a 512B page boundary */
    KEEP (*(.bootloader_data))  /* .bootloader_data sections */
    KEEP (*(.bootloader_data*)) /* .bootloader_data* sections */
    . = ALIGN(512);
  } >FLASH

CodePudding user response:

The sensible way to do this is to find the command in the linker script telling it to back off from touching that memory in the first place. Because why would you want it do be erased only to filled up with 0xFF again? That only causes unnecessary flash wear for nothing.

Something along the lines of this:

.bootloader_data (NOLOAD) :
{
  . = ALIGN(512);
  *(.bootloader_data *)
} >FLASH

CodePudding user response:

I would use a union of your struct together with an array of the correct size, then initialize the array member.

union {
    struct BlData_t data;
    uint8_t bytes[sizeof(struct BlData_t)];
} data_with_ff = {
    .bytes = {
        [0 ... sizeof(struct BlData_t) - 1] = 0xff
    }
};

You can then access your struct as data_with_ff.data, defining a pointer or macro for convenience if you wish.

Try on godbolt

(Readers should note that the ... in a designated initializer is a GCC extension; since the question was already using this feature and is tagged I assume that is fine here. If using a compiler that doesn't have it, I don't know another option besides .bytes = { 0xff, 0xff, 0xff ... } with the actual correct number of 0xffs; you'd probably want to generate it with a script.)

CodePudding user response:

If you truly need to do this initialization and in pure standard C, then you can wrap your inner struct inside an anonymous union (C11), then initialize that one using macro tricks:

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} };

This method could also be applied on whole struct basis, if you for example want to initialize a struct array with all items set to the same values at compile-time.

  • Related