0

Setup

#define functionA(str) functionB(PSTR(str))

void functionB(char const* str) { ... something, e.g. print str... }

void functionC(char const* str) {
    functionA("Hello World");       // this one work
    functionA(str);                 // however this doesn't work
}

Problem

I have a function function B which I try to use. If I simply call it with "some string" it works perfectly. However if I try to call it in functionC with the argument str, the compiler returns the error "invalid initializer" and the message "in expansion of macro PSTR". How can I fix this, where is my problem?

EDIT - additional information

The program runs on an AT Mega and the PSTR is also from AT-Mega

#define PSTR(s) ((const PROGMEM char *)(s))
#else  /* !DOXYGEN */
/* The real thing. */
# define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
#endif /* DOXYGEN */

#define PROGMEM __ATTR_PROGMEM__

#ifndef __ATTR_PROGMEM__
#define __ATTR_PROGMEM__ __attribute__((__progmem__))
#endif
Vabeyeb
  • 1
  • 1
  • 3
    What is the macro PSTR? – user253751 Nov 28 '19 at 12:47
  • 2
    don't describe the error message, paste it – Jean-François Fabre Nov 28 '19 at 12:49
  • I'm not quiet sure, it was given. It is part of the microcontroller ATMega. Online I found `#define PSTR(s) \ ((const PROGMEM char *)(s)) ` but there you have the next macro... – Vabeyeb Nov 28 '19 at 12:49
  • With a link to the [doc](http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#ga05ca900ebf7cd121be73c654d9ccb3eb), it's easier to understand – Phantom Nov 28 '19 at 12:50
  • 1
    isn't it supposed to be `const char* str` ? – PhoenixBlue Nov 28 '19 at 12:53
  • @Jean-FrançoisFabre the error message is just "invalid initializer" and "in expansion of macro 'PSTR'", I don't know how that helps – Vabeyeb Nov 28 '19 at 12:54
  • @PhoenixBlue tried it, still doesn't help – Vabeyeb Nov 28 '19 at 12:55
  • 1
    OK. First change it to `const char* str` then show us the implementation of `PSTR` – PhoenixBlue Nov 28 '19 at 12:57
  • Maybe take a look at this: https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const/1143272#1143272 – Adrian Mole Nov 28 '19 at 13:00
  • Try if it compiles with `#define PSTR(s) ((const char *)(s))` – Jabberwocky Nov 28 '19 at 13:00
  • @Jabberwocky PSTR is not defined by me, it's given by the microcontroller – Vabeyeb Nov 28 '19 at 13:02
  • ... and are you sure your usage of the `PSTR` macro is appropriate here? – Jabberwocky Nov 28 '19 at 13:02
  • Yes, this part was given. I had the idea to use another function (functionC) to call functionA, however I'm not sure if this works. It works with "string" but not if I try to use the string passed over as an argument to functionC – Vabeyeb Nov 28 '19 at 13:04
  • @Vabeyeb yes we know it's not defined by you, but it's still usefull to know what is it... – Jabberwocky Nov 28 '19 at 13:04
  • _"this part was given"_: given by whom? Maybe syou should ask _that_person. – Jabberwocky Nov 28 '19 at 13:06
  • 1
    Progmem (`PSTR`) strings occupy a different address space – even if you manage to pass the pointer to a function expecting a regular (RAM) string, it would not be able to use it correctly (since it's not in RAM). You need to copy the `PSTR` to RAM first in order to pass it to such a function. – Arkku Nov 28 '19 at 13:13

1 Answers1

3

You cannot mix program space and regular strings, since they are stored in different memory spaces. The AVR architecture separates data and program memory, and regular variables/strings live in the data memory (RAM). But since RAM is often very limited on these devices, constant data (such as strings) may be stored in program space to avoid using RAM. The PSTR macro is provided to do this for string literals.

The reason for your error with functionA(str) is simply that it ends up using the macro as PSTR(str), and PSTR only works with string literals since you cannot place data in program space at runtime. But also note that while PSTR("Hello world") works, your functionB must specifically expect a program space string or it will treat the pointer as though it pointed to RAM (which it doesn't).

To use a program space string, you may either take a PSTR as an argument and handle it with the pgm_* functions/macros (such as pgm_read_byte), or first copy the PSTR to RAM (such as with strcpy_P) and then pass that to a function expecting a regular string. See avr/pgmspace.h.

Arkku
  • 41,011
  • 10
  • 62
  • 84