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.

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.

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..

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.