It is a shame that gcc only supports the __flash
qualifier in C mode,
not in C++, so we have to use PROGMEM
instead. Unlike __flash
, which
qualifies a variable just like const
, the PROGMEM
attribute only has
effect when allocating room for a variable. Once the allocation is done,
the compiler forgets about the attribute. In particular, a declaration
such as
const PROGMEM char* text;
does not allocate flash space, so it generates the warning
warning: ‘__progmem__’ attribute ignored [-Wattributes]
const PROGMEM char* text;
^
You can thus forget the attribute when declaring a pointer, as there is
no such thing as a “pointer to PROGMEM
”. You just use a const char *
instead.
Now, the second issue is that, as far as Serial.println()
is
concerned, the pointer above is a plain const char *
, so it will
interpret it as an address in RAM, and print garbage. If you want
Serial.println()
to know you are giving it an address in flash, you
should provide it with a const __FlashStringHelper*
pointer.
Here is the solution I propose. Tested on an Uno-compatible board:
class A
{
public:
A(const char* s)
: text(reinterpret_cast<const __FlashStringHelper *>(s)) {}
const __FlashStringHelper* text;
};
void setup()
{
A a{PSTR("Hello World!")};
Serial.begin(9600);
Serial.println(a.text);
}
void loop(){}
Edit: After seeing the last version of Juraj’s answer, I must say
that I agree with him. Since we are using the Arduino API, it makes more
sense for the constructor to take a const __FlashStringHelper*
, and
for the caller to use the F()
macro.
a.text = F("Hello World!");
do what you want?const __FlashStringHelper*
- it'sconst char*