Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

accessing data from structure in flash

I am using an Atmel AVR and am trying to access data from a structure which is stored in flash (program) memory.

The structure is:

typedef struct {
    uint8_t width;
    uint8_t height; // row number 0 to 5
    uint8_t images; // how many frames does this bitmap have
    uint8_t data[]; // the actual pixel data
} bitmap_t;

the data is:

    __flash   static const bitmap_t bmp_stereo2  = {14,1,1,{126,129,60,66,24,36,60,60,36,24,66,60,129,126}};

I'm trying to access the data with (partial code shown)...

void lcd_bitmap2(const bitmap_t *bit, uint8_t id, uint8_t posx, uint8_t posy) {
    uint8_t x;
    uint8_t y;  

    const uint8_t bw  = pgm_read_byte(&bit->width);   // this works -- I can print out to serial
    const uint8_t bh  = pgm_read_byte(&bit->height);  //this also works -- I can print out to serial
    // this doesn't work
    const uint8_t  *data = pgm_read_word(&bit->data); // I get: - initialization makes pointer from integer without a cast [enabled by default] 

    const uint8_t  *data = (uint8_t *)pgm_read_word(&bit->data); // this also doen't work (no warning, but wrong data read out)

    //rest of function...

So I can access the width, height and image variable, but not the data part of the structure. It all works if I don't store in flash - It's my retrieval and only has a problem with the data array part of the structure (width, height and image are read ok)

like image 201
Russell Avatar asked Apr 30 '26 16:04

Russell


1 Answers

TL;DR: you cannot safely do that in standard C.

Given this definition ...

typedef struct {
    uint8_t width;
    uint8_t height; // row number 0 to 5
    uint8_t images; // how many frames does this bitmap have
    uint8_t data[]; // the actual pixel data
} bitmap_t;

... bitmap_t.data is a "flexible array member":

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed [...].

[C2011 6.7.2.1/18; emphasis added]

Examples in the standard clarify that it is invalid to provide an initializer for a flexible array member, as your code attempts to do. Moreover, there is no reason to expect that any space at all will be allocated for the contents of a flexible array member of an object with static or automatic storage duration, such as yours. Flexible array members are useful only in conjunction with dynamically allocated objects, unless in an implementation that makes promises in this area beyond those required by the standard.

Accessing the flexible array member of your statically allocated object therefore produces undefined behavior. This is not directly related to the actual location of the storage, though it is possible that the UB manifests differently when it is in flash. (After all, the behavior is undefined.) To use objects of type bitmap_t in the way you are trying to do, you will need to modify that type so that its data member has a complete type (i.e. fixed dimension(s)).

like image 181
John Bollinger Avatar answered May 02 '26 05:05

John Bollinger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!