Hardcoded strings and PSTR

Is there a simple solution to the PSTR issue?

I recently got all excited when I discovered I could use.....
#include <avr/pgmspace.h> and PSTR()
To write all my hardcoded strings to program memory rather than data memory. I duly changed lots of hardcoded stuff

Serial.println(“Hello world”) became Serial.println(PSTR(“Hello world”))
And
strcpy(errMessage,("not plugged in")) became strcpy(errMessage,(PSTR("not plugged in")))

Throughout my code, only to discover it didn’t work and I had to undo everything!

I checked the forum, and it’s obviously a known issue (wish I’d checked before I’d made the changes). Is there a fix to this issue, or maybe a better way of doing this? I did discover a couple of posts about this, but they seemed to only work for Serial.println, and not for all inline strings.

Try this...
http://arduiniana.org/libraries/flash/

Why did you undo everything? Most of the std library functions have _P equivalents that work with strings in flash. strcpy_P for example...

The problem isn't with the _P equivalents, it with the interpretation of hardcoded string literals. This command....
Serial.println(PSTR(“Hello world”))
Ought to work but doesn't (not in arduino world anyway). This forum hosts threads about this, but the most recent one I could find was over a year old and I was hoping for some fresh developments since then.

I'll try the flash library.

This command.... Serial.println(PSTR(“Hello world”)) Ought to work

No it ought not to work! Serial.println expects a pointer into SRAM and you are trying to pass it a pointer into flash. The Harvard architecture of the AVR MCU means that address N could be in flash or it could be in SRAM and so a function (e.g. println) that receives a memory address must know in which memory bank it lies. The convention is that ordinarily named functions expect SRAM addresses and those with an _P suffix expect flash addresses in at least one of their parameters.

If you want println to accept a flash address then you could subclass it and add _P methods or you will need to temporarily copy your string out of flash like this:

char *buffer;
buffer=(char *)malloc(strlen_P(progmemstring)+1);
strcpy_P(buffer,progmemstring);
Serial.println(buffer);
free(buffer);

Lima7:
Ought to work but doesn't (not in arduino world anyway).

It is not so much the Arduino or the C compiler, but the fact that the AVR microcontroller is based on Harvard architecture (as opposed to von Neumann). Anything in flash memory requires different low level access code on an AVR. That is, a function needs to know whether it should fetch data from flash or from RAM. The address of the data is not sufficient by itself. This is why you see duplication of functions with a _P suffix.

I’ve used PSTR quite a lot and find it useful. The only thing you need is to write your own “print_P” function as it is not available in the standard core library. An implementation could be as follows:

// print a character string from program memory
void print_P(const char *str)
{
  uint8_t val;
  while (true) {
    val=pgm_read_byte(str);
    if (!val) break;
    Serial.write(val);
    str++;
  }
}

dafid:
I think the problem is not with Arduino, but with the GCC C++ compiler.
I had similar problems in doing this in a very small project using C++, and make files etc - and worked through the examples discussed in the winavr documentation - to find the I could not make PSTR() work at all.

Apparently the PSTR() macro uses extensions to the C language, that happen to work sometimes and in some versions of the C++ compiler, but that there are issues with these extensions in C++, so they are not supported.

There is absolutely nothing wrong or unsupported about PSTR in either the latest version of g++ or the somewhat dated version shipped with the Arduino IDE. Please post any problematic code that you have and I'll be happy to correct it for you.

The "problem" seems to be that C++ does not recognize PSTR as a different data type compared to char*, so functions like Serial.print() don't know which ones they've been passed. the "flash" library does some clever things to get around this, but I usually just define a new function:

void flashprint (const char p[])
{
    byte c;
    while (0 != (c = pgm_read_byte(p++))) {
	Serial.write(c);
    }
}

#define fp(string) flashprint(PSTR(string));
1 Like

Hi Andy,

I had issues with PSTR() and the release winavr (20100110) over christmas new-year break.

I kept getting errors from the compiler - like the ones reported in this thread..
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=57011

I did not find any comments about how it had could be resolved..

As far as I could see there was no way to convince the GCC C++ compiler that the string was initialised and hence legal to put in PROGMEM.

I did find (but will need to look for it again) some statements like I reported above, saying that issues in PROGMEM could relate to parsing the more complex C++ grammar.

I will post some sample code and and errors in a bit

Ah yes, the "warning: only initialized variables can be placed into program memory area" warning. It's completely bogus and can be ignored - the compiler does the correct thing anyway. This one got on my nerves so much that I went into the gcc source and removed the warning message so I could use the -Werror and -Wall flags without this annoyance breaking the build.

Hi Andy,

I went back and tried to replicate my problems from end of dec. What I found lines up with your statement that the warning does not mean anything.

I am cranky with myself because i spent more than 2 days looking at this warning, and reading messages on the web, but did not think to check the avr-size of the result.

It is still agravating. Do you know of a fix that might arrive in avr-c++ anytime soon?

I am going to delete my earlier comment - I see it coming up in Google now :frowning: - and it is wrong.

Dave