Messing about PROGMEM and F()

Hi all XD I'm arduino newbie

Looking for save SRAM memory i developed a function to work with all my char arrays in PROGMEM because I have not found anything like in the web and i need to store all my strings in PROGMEM without move it to to arrays or something complicated and annoying.
The nearest approach i found: PROGMEM and F() macro as parameters for function - Programming Questions - Arduino Forum but i need a function using a char array. I prefer use char arrays to program. For me is easy to work with it.

My function:

char * progmemToString(const __FlashStringHelper *ifsh) {
  static char stringTMP[50];             // I use 50 because is my longest string + 1 
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  byte n = 0;
  while ( pgm_read_byte ( p ) != NULL )
    stringTMP[n++] = pgm_read_byte (p++);
  stringTMP[n] = '\0';
  return ( stringTMP );
}

My only doubt is with stringTMP: there is a safer way to use a char array without declaring its size? I know actually i am loosing 50 bytes of SRAM declaring stringTMP[50].

My purpose is use the F() function in all the program. Arduino only allow to use F() with classes that allow print, like Serial.print. When i call a routine/function with a string parameter in F() format i receive a compiler error: " cannot convert 'char*' to 'const __FlashStringHelper*' ". To solve it i have just to overload my routine/function like this:

My function: boolean compare(char * myCharArray) { code... more code... }
Overload: boolean compare(const __FlashStringHelper *ifsh) { compare( progmemToString(ifsh) ); }

And now i can write a program with things like this: compare( "My text" ); or like that: compare( F("My text") );
For me is the simpliest way to work with strings and move it to PROGMEM and the only way i found without move my strings in the program..

I used this method in a huge program with a variety of routines/functions without problem and found is consistent. Only has one failure: if i call a routine with F() as a parameter and within the routine i call another routine with another F() as a parameter, the arduino goes totally crazy. One arduino program memory killed testing it.

What do you think? Is a correct mode to work with PROGMEM or is it dangerous?

What do you think?

The idea is good but there are cases when your approach will fail:
genericly your code can only handle one PROGMEM string at the time.

strcmp(progmemToString(strA), progmemToString(strB));

both would point to the same (SRAM) buffer.

Is a correct mode to work with PROGMEM or is it dangerous?

serious bug : buffer overflow

char * progmemToString(const __FlashStringHelper *ifsh) 
{
  static char stringTMP[50];             // I use 50 because is my longest string + 1 

  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  byte n = 0;
  while ( (pgm_read_byte ( p ) != NULL)   &&  (n < 49) )  // <<<< buffer overflow prevention, keep space for \0
  {
    stringTMP[n++] = pgm_read_byte (p++);
  }
  stringTMP[n] = '\0';
  return ( stringTMP );
}

Any good reason for not using strcpy_P, strncpy_P etc?

AWOL:
Any good reason for not using strcpy_P, strncpy_P etc?

IT WORKS !!!!!! XD XD XD You are the best. It's a clean and simple solution XD

char * progmemToString(const __FlashStringHelper *ifsh) {
  static char stringTMP[50];             // I use 50 because is my longest string + 1 
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  strcpy_P(stringTMP,  (char*)p); 
  return ( stringTMP );
}

The only doubt i have is the control of the length of the string. robtillaart solved before but it's impossible to apply with strcpy_P. Maybe strcpy_P prevents this fail?

The only doubt i have is the control of the lenght of the string robtillaart commented before.

Which is why AWOL also suggested strncpy_P.

PaulS:

The only doubt i have is the control of the lenght of the string robtillaart commented before.

Which is why AWOL also suggested strncpy_P.

Looking at info of strncpy_P strncpy_P uses the lenght of the string as parameter.
I don't have the lenght of the string when using F(), but i'm thinking if i use the maximum legth of stringTMP (actually 49) and strncpy_p fills it with nulls between the progmem string and its end, sounds interesting.

So, the code is:

char * progmemToString(const __FlashStringHelper *ifsh) {
  static char stringTMP[50];             // I use 50 because is my longest string + 1 
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  strncpy_P(stringTMP,  (char*)p, 49); 
  return ( stringTMP );
}

I don't have the lenght of the string when using F()

Do you know what the definition of a string is?

Are you trying to dynamically size the buffer? Forget that crap.

Or, are you trying to make sure that you don't write beyond the end of the static buffer?

I don't have the lenght of the string when using F()

If speed isn't an issue, you could always use strlen_P to get the length.

PaulS:

I don't have the lenght of the string when using F()

Do you know what the definition of a string is?

Are you trying to dynamically size the buffer? Forget that crap.

Or, are you trying to make sure that you don't write beyond the end of the static buffer?

Sorry, i modified my last message at the same time you wrote the answer. I'm super editor XD I edit always.

My answer is option 2: i'm trying to make sure that i don't write beyond the end of the destination array stringTMP

My answer is option 2: i'm trying to make sure that i don't write beyond the end of the destination array stringTMP

Then, pYro_65's answer is what you need.

My question was designed to get you to research what strXXX functions had strXXX_P versions.

PaulS:

My answer is option 2: i'm trying to make sure that i don't write beyond the end of the destination array stringTMP

Then, pYro_65's answer is what you need.

My question was designed to get you to research what strXXX functions had strXXX_P versions.

Applying str function to this problem is AWOL's idea a few time ago (A really good idea XD). I have not yet had time to process the implications and the ramifications. You 're right. I need to think about that.

Anyway, i think there is 2 options now. One option is left the last code i posted, with strcpy_P and the other option is change it with this line

strncpy_P( stringTMP,  (char*)p, strlen_P(p) );

The question is: The legth control is necessary or the first option serves well its purpose, filling automatically the rest of the destination array with nulls? Maybe i need to think about speed or having trouble with large strings in PROGMEM larger than 49 chars and add more lines to control it. Pros and cons, mmmm.....

What do you think?

Thanks all XD

It shouldn't ever be necessary to fill the excess space in the destination array with nulls.
The first one should be sufficient.

strncpy_P( stringTMP,  (char*)p, strlen_P(p) );

If you think about this for a while, you'll see that it is pretty poor code.

What happens if the string is 200 characters long? How is that possibly going to fit in the 50 element array?

Which length is the limit on the amount of data that strncpy_P() should copy?