0

I have a class which has a const char * property:

 class A
 {
 public:
 const PROGMEM char* text;
 };
 void setup()
 {
 // A a{"Hello World!"};
 // A a{PSTR("Hello World!")};
 A a;
 a.text = PSTR("Hello World!");
 Serial.begin(9600);
 delay(30);
 Serial.println(a.text);
 }
 void loop()
 {
 }

I’d like to spare some RAM using PROGMEM.

How to initialize a object then?

Obviously, it can’t be like this:

 A a{PSTR("Hello World!")};

This will do:

 A a;
 a.text = PSTR("Hello World!");

However, I need to pass string to the constructor.

asked Feb 22, 2020 at 15:38
2
  • does a.text = F("Hello World!"); do what you want? Commented Feb 22, 2020 at 21:03
  • 1
    @dandavis, it does not. you've missed that a.text is not const __FlashStringHelper* - it's const char* Commented Feb 22, 2020 at 21:59

2 Answers 2

2

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.

answered Feb 22, 2020 at 17:34
0
3

const char* text; is a pointer to constant not a constant pointer (char * const text is a constant pointer). So you can assign a pointer to a constant char array to const char* text; even a pointer to an array in PROGMEM.

The compiler doesn't know the difference between a PROGMEM pointer and a pointer in SRAM. It is on you to work in code with a pointer to PROGMEM the right way.

so remove PROGMEM from const PROGMEM char* text;


add constructor to initialize an object.

A(const char* _text) {
 text = _text;
}

and then

A a(PSTR("Hello World!"));

EDIT:

you could use Arduino's F() macro and __FlashStringHelper type, because it is supported by Serial print and co.

class A
{
public:
 A(const __FlashStringHelper* _text) {
 text = _text;
 }
 const __FlashStringHelper* text;
};
void setup()
{
 A a(F("Hello World!"));
 Serial.begin(9600);
 delay(30);
 Serial.println(a.text);
}
void loop()
{
}

__FlashStringHelper type is trick to distinguish PROGMEM strings from char arrays in SRAM..

answered Feb 22, 2020 at 16:05
4
  • This is not an answer on my question. How to store strings in flash memory? Strings must be passed to the contructor. Commented Feb 22, 2020 at 16:48
  • 1
    it is unclear what is what you don't know. I enhanced the answer Commented Feb 22, 2020 at 17:25
  • Hum... Your solution won't let use Serial.println. And added user-defined constructor does not any difference here. Commented Feb 22, 2020 at 22:03
  • @zhekaus, yes, your question combined 3 problems. Edgar got them all, but the true solution is to use F macro, not PSTR, if possible. I enhanced the answer Commented Feb 23, 2020 at 6:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.