"PROGMEM const char *str" treated as "const char *str"?

I was testing out the use of flash using PROGMEM and F("") in Arduino 1.6.5-r5 with Uno and try to have two functions accepting different pointers as below:
void sendStr(PROGMEM const char *str) { … } // point to flash
void sendStr(const char *str) { … } // point to RAM

I notice that the compiler ignores the PROGMEM with the warning (warning level was set to “More”)
progmem’ attribute ignored [-Wattributes]
Thus giving error:
‘void sendStr(const char*)’ previously defined …

I thus have to use different names for the 2 functions
void sendStrF(PROGMEM const char *str) { … }
void sendStr(const char *str) { … }

However, I have to to be very conscious that the string I use is in RAM or Flash and use the right function. Using the wrong function has no compilation error but give wrong result.

Program below works.

const char PROGMEM flashStr[] = " flash str"; // FLASH
const char ramStr[] = " RAM str"; // RAM
// -------------------------------------------------
void sendStrF(const __FlashStringHelper *str) {
    uint8_t c;
    PGM_P p = reinterpret_cast<PGM_P>(str);
    while ((c = pgm_read_byte(p++)) != 0) {
        Serial.write(c);
    }
}
// -------------------------------------------------
void sendStrF(PROGMEM const char *str) {
    uint8_t c;
    PGM_P p = reinterpret_cast<PGM_P>(str);
    while ((c = pgm_read_byte(p++)) != 0) {
        Serial.write(c);
    }
}
// -------------------------------------------------
void sendStr(const char *str) {
    uint8_t c;
    while ((c = *str++) != 0) {
        Serial.write(c);
    }
}
// -------------------------------------------------
void setup() {
    Serial.begin(57600);
    sendStrF(F("Hai"));
    sendStrF(flashStr);
    sendStr(ramStr);
}
// -------------------------------------------------
void loop() {
}

However, if I change these statements:
sendStrF(flashStr);
sendStr(ramStr);
to
sendStr(flashStr);
sendStrF(ramStr);

There is no compilation error (but the same old warnings on PROGMEM) and get wrong run-time result.

Is there anyway that I can overcome this problem?

Progmem means nothing to the compiler (only the linker uses it). You cannot mark a function parameter as PROGMEM and expect anything different to the non PROGMEM version, its a data attribute not a type modifier, so it is completely ignored.

void sendStr(PROGMEM const char *str) { ... } // point to flash
void sendStr(const char *str) { ... } // point to RAM

They point to where ever the passed in pointer points. And both functions like the error says, are the same thing.

However, I have to to be very conscious that the string I use is in RAM or Flash and use the right function. Using the wrong function has no compilation error but give wrong result.

You could make an artificial type. progmem is an attribute, not a type.

Attempting to use typedef and encounter very strange compiler behaviour This is the code

typedef char C;

C astr[] = " a str";
// -------------------------------------------------
void sendStr(C *str) {
    uint8_t c;
    while ((c = *str++) != 0) {
        Serial.write(c);
    }
}
// -------------------------------------------------
void setup() {
    Serial.begin(57600);
    sendStr(astr);
}
// -------------------------------------------------
void loop() {
}

Get these errors!
test2:2: error: variable or field ‘sendStr’ declared void
test2:2: error: ‘C’ was not declared in this scope
test2:2: error: ‘str’ was not declared in this scope
variable or field ‘sendStr’ declared void

Tried this in CodeBlock as a .cpp program and is fine:

#include <stdio.h>
#include <stdint.h>

typedef char C;
C astr[] = " a str";
// -------------------------------------------------
void sendStr(C *str) {
    uint8_t c;
    while ((c = *str++) != 0) {
        putchar(c);
    }
}
// -------------------------------------------------
void setup() {
    sendStr(astr);
}
int main() {
    setup();

Could not figure out the errors in Arduino.

Also could not figure out how to create an artificial type to improve checking by the compiler. At the meantime, will live with the two different functions and carefully use them appropriately.

Thanks for pointing out the attribute thing and suggestion.

Since the language is called C(++) I wouldn't personally be using a variable named C.

However the real problem is that you need a function prototype, due to the way the IDE works. This compiles:

typedef char foo;
foo astr[] = " a str";
// -------------------------------------------------
void sendStr(foo *str);   // prototype
void sendStr(foo *str) {
    uint8_t c;
    while ((c = *str++) != 0) {
        putchar(c);
    }
}
// -------------------------------------------------
void setup() {
    sendStr(astr);
}
int main() {
    setup();
}

The sketch looks like this after the IDE has done its tricks:

#line 1 "sketch_sep28a.ino"

#include "Arduino.h"
void sendStr(C *str);
void setup();
void loop();
#line 2
typedef char C;

C astr[] = " a str";
                                                    
void sendStr(C *str) {
    uint8_t c;
    while ((c = *str++) != 0) {
        Serial.write(c);
    }
}
                                                    
void setup() {
    Serial.begin(57600);
    sendStr(astr);
}
                                                    
void loop() {
}

The need of function prototype is a surprise. Since the typedef is right at the top and the function is defined before it is called, the code should be acceptable as tested in CodeBlock.

Rather confused. Can we consider the situation as rather not user-friendly?

Thanks for all the helps.

I have been able to trick the IDE into doing what I want.

Add throw() to the end of your function declaration, then you do not need the prototype (IDE does not generate one for you).

However the function must be above all the code that uses it.

void sendStr(C *str) throw(){
    uint8_t c;
    while ((c = *str++) != 0) {
        Serial.write(c);
    }
}

Add throw() to the end of your function declaration, then you do not need the prototype (IDE does not generate one for you).

That is very dodgy, and a kludge. The compiler does not support exceptions. See:

How to avoid the quirks of the IDE sketch file pre-preprocessing

Nope, its pure C++. So what if exceptions aren't enabled (means nothing to this argument). throw without any parameters specifically tells the compiler that no exception is thrown.

By the way, I thought for INO file, function prototype is not essential as Arduino treat it special, different from normal CPP files which have to adhere to strict rules. Functions defined in later part of the INO file can be accessed by functions above it without prototype.

But now the strange error messages are solved by having a prototype which is not required in CPP, is quite strange for common user who may not have idea what is going on behind the compilation process.

Back to the original issue. Not sure how to ensure make "PROGMEM const char" to be treated differently from "const char" so that one will not call the function with a wrong data.

Use one of your original approaches.

void sendStr(const __FlashStringHelper *str){

Add a define to make things nicer looking:

#define FSH const __FlashStringHelper *

Then pass your value like this:

const char arr[] PROGMEM = "My PGM data";

//...

void func(){
  sendStr( (FSH) arr );

  sendStr( F("This works too!") );
}

If you want to do it without knowing whether the object at the point of call is in PROGMEM... basically you really need to drop this idea unless you are using something like templates which really deal with the possibility of unknown types. As far as you're going you'll always know the data is in PROGMEM.

If you have something that only accepts a char* type or similar, and it needs to know whether its in flash or not, then you can add a parameter to inform it of this (bool flag or such).

If you are using templates, let me know and I can show you how.

wongss:
But now the strange error messages are solved by having a prototype which is not required in CPP, is quite strange for common user who may not have idea what is going on behind the compilation process.

Yes, prototypes are required by C++ for things which have not yet been defined. It's just that the IDE tries to reduce your need to have them for functions or datatypes you have not yet declared by generating them automatically. A process that sometimes fails.

Thanks for the helpful suggestion to use

#define FSH const __FlashStringHelper *

I will use that though it involves explicit casting.

It is hard to accept that the simple code I tried, that is acceptable in C/C++, was compile with strange errors. I really thought there was a bug in Arduino.

I've been doing Arduino on esp8266 in recent weeks.

Really grateful for the suggestion to use (FSH) it works perfect there too!
It helps to save lots of RAM!

progmem is a storage class specifier like auto, register, static etc and not part of the type as such. So you can't typedef it. I get the impression that the compiler really can't tell the difference between the two types of pointers - it's up to you to know what you are dealing with.