PROGMEM on compound-literal arrays

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

PROGMEM on compound-literal arrays

Paul "LeoNerd" Evans
((TLDR: PROGMEM on compound-literal arrays is silently ignored.
  Please either implement or make it a noisy warning/error.))



If I define a function that takes a byte array, e.g.

  void i2c_write(size_t len, const uint8_t *data);

I find it nice to be able to call that with compound-literal arrays
inline:

  i2c_write(4, (const uint8_t[]){0x10, 0x20, 0x30, 0x40});

((The reason I'm using this inline notation rather than a static
  declaration made elsewhere is that my data in fact comes from a
  build-time translation step, and most of the arguments to the function
  call are embedded with an #include directive to embed the data in the
  source code.))

If I want to store the data in PROGMEM instead and write a _P version,
then this syntax won't do:

  i2c_write_P(4, (const PROGMEM uint8_t[]){0x10, 0x20, 0x30, 0x40});

While it does parse and compile successfully, the data doesn't end in
in PROGMEM, so the pgm_read_byte() function doesn't find it, and
returns junk. There's no compile-time warning or error that it hasn't
honoured it though, so debugging this failure can be hard.

The following syntax does work as an alternative:

  i2c_write_P(4, ({
    static const PROGMEM uint8_t data[] = {0x10, 0x20, 0x30, 0x40};
    data;
  }));

I.e. a statement-expression that embeds a static PROGMEM declaration
and yields it.

Would it be possible to make the former syntax work though?

--
Paul "LeoNerd" Evans

[hidden email]      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/

_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list

attachment0 (188 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: PROGMEM on compound-literal arrays

Georg-Johann Lay-2
Paul "LeoNerd" Evans schrieb:

> ((TLDR: PROGMEM on compound-literal arrays is silently ignored.
>   Please either implement or make it a noisy warning/error.))
>
>
>
> If I define a function that takes a byte array, e.g.
>
>   void i2c_write(size_t len, const uint8_t *data);
>
> I find it nice to be able to call that with compound-literal arrays
> inline:
>
>   i2c_write(4, (const uint8_t[]){0x10, 0x20, 0x30, 0x40});
>
> ((The reason I'm using this inline notation rather than a static
>   declaration made elsewhere is that my data in fact comes from a
>   build-time translation step, and most of the arguments to the function
>   call are embedded with an #include directive to embed the data in the
>   source code.))

Well, code like

i2c_write (
     #include "data.def"
);

where data.def contains

4, (const uint8_t[]){0x10, 0x20, 0x30, 0x40}

might be in order for auto generated code, but solutions that first
define a variable and then use it by its name is superior.  One reason
is that multiple uses of the same ad hoc data don't generate different
instances.

> If I want to store the data in PROGMEM instead and write a _P version,
> then this syntax won't do:
>
>   i2c_write_P(4, (const PROGMEM uint8_t[]){0x10, 0x20, 0x30, 0x40});
>
> While it does parse and compile successfully, the data doesn't end in
> in PROGMEM, so the pgm_read_byte() function doesn't find it, and
> returns junk. There's no compile-time warning or error that it hasn't
> honoured it though, so debugging this failure can be hard.
>
> The following syntax does work as an alternative:
>
>   i2c_write_P(4, ({
>     static const PROGMEM uint8_t data[] = {0x10, 0x20, 0x30, 0x40};
>     data;
>   }));
>
> I.e. a statement-expression that embeds a static PROGMEM declaration
> and yields it.
>
> Would it be possible to make the former syntax work though?

No, PROGMEM (same for __flash et al.) only work for data in static
storage.  That's because sections are used to locate such data.  Data of
automatic storage duration like in your 1st example lives on the stack.

Note that your 2nd example will not work with automatic data because its
lifetime ends at the end of the enclosing block, hence using its address
after the end of the block is undefined behaviour (using a dangling
reference to a declined local).

Johann


_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: PROGMEM on compound-literal arrays

Paul "LeoNerd" Evans
On Sun, 30 Oct 2016 20:17:51 +0100
Georg-Johann Lay <[hidden email]> wrote:

> Well, code like
>
> i2c_write (
>      #include "data.def"
> );
>
> where data.def contains
>
> 4, (const uint8_t[]){0x10, 0x20, 0x30, 0x40}
>
> might be in order for auto generated code, but solutions that first
> define a variable and then use it by its name is superior.  One
> reason is that multiple uses of the same ad hoc data don't generate
> different instances.

Ahyes, multiple references. Given as these are image bitmaps for an
OLED display, perhaps it would be best for me to put them in some
variables after all.

--
Paul "LeoNerd" Evans

[hidden email]      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/

_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Loading...