I would like to pass a formatted string to a method that accepts a __FlashStringHelper. Here is the method signature:
void myMethod(const __FlashStringHelper *str);
I have been using snprintf to format my string:
char cmd[30];
snprintf(cmd, 30, "There are %d seconds in a minute", 60);
myMethod(F(&cmd[0]));
Clearly the above doesn't work but how can I format a Flash String?
EDIT: I need to include an integer variable in my flash string. In the example above, '60' is a variable.
uint8_t nSeconds = 60;
char cmd[30];
snprintf(cmd, 30, "There are %d seconds in a minute", nSeconds);
myMethod(F(&cmd[0]));
1 Answer 1
Direct answer
F()
takes immutable string literals, that are known at compile time, and places them into flash ("PROGMEM") instead of RAM. snprintf()
creates strings at runtime and places them into a mutable array. The two things are fundamentally incompatible.
Limited compile-time concatenation
A very limited form of what you're trying to do could probably done like this:
#define MY_STRINGIZE(x) #x
myMethod(F("There are " MY_STRINGIZE(60) " seconds in a minute"));
This expands to:
myMethod(F("There are " "60" " seconds in a minute"));
Adjacent string literals are concatenated together, which makes this:
myMethod(F("There are 60 seconds in a minute"));
All that said, you could just write 60 in there directly. And there's none of snprintf
's formatting capabilities possible here.
There is not a compile-time version of snprintf
available in Arduino. And I don't think the features of the C++ (or C) language are there to support the creation of one either. Odds are there is a better way of achieving what you really want to do.
Working around this altogether
Often it's not necessary to concatenate strings at all, particularly if you're just to turn around and write them to a Stream
, or more generally Print
subclass, e.g. Serial
, LCD
, SDFile
, SoftwareSerial
, etc. Concatenating things for you is a large part of what these do. It is not necessarily to do it yourself in advance.
If you have a string literal and constant (or variable) and want to keep as much of it out of RAM as possible, using two separate .print()
/.println()
helps you do this:
printCapableThing.print(F("AT+CIPSTAT="));
printCapableThing.println(index);
F()
places"AT+CIPSTAT="
into flash.- If index is a constant it will also wind not being resident in RAM.
Side note
I realize you're asking about, getting as much into flash as possible, but I also can't help but point out this same basic technique applies to this otherwise awful idea, for somewhat different reasons:
Serial.println(String(F("Key ")) + keyname + " : " + value);
This creates a horrific mess of allocations and deallocations and unnecessary copying, where if you just let the Stream/Print object do its job by calling print()
/println()
multiple times. The result code is more reliable, smaller, and where not I/O-bound, faster when you do.
-
I guess what he really needs is not a compile-time version of
snprintf
(that would be quite useless), but amyMethod
that takes aconst char*
.PMF– PMF02/21/2021 20:25:29Commented Feb 21, 2021 at 20:25 -
I can absolutely see uses for compile-time string formatting. Though yes, it probably will come down to the latter.timemage– timemage02/21/2021 20:27:18Commented Feb 21, 2021 at 20:27
-
I mean you could be writing an implementation for
snprintf(cmd, 30, F("There are %d seconds in a minute"), 60);
(not hard to do with a temporary copy). But something likesnprintf(F("..."), 30, F("Result is %d"), 60);
cannot work, because the result of snprintf can certainly not be in flash.PMF– PMF02/21/2021 20:31:05Commented Feb 21, 2021 at 20:31 -
2You could, but you needn't. There already exists an
snprintf_P
variant capable of taking the format string from PROGMEM. You'd probably usePSTR
there instead though. I'm not seeing the relevance of this though.timemage– timemage02/21/2021 20:32:50Commented Feb 21, 2021 at 20:32 -
Thank you all for you responses! @timemage: The '60 seconds in a minute' isn't my exact use case, my use case requires context which I tried to omit. Mostly, I am trying to understand how I can format a string in program memory.P. Avery– P. Avery02/21/2021 21:02:25Commented Feb 21, 2021 at 21:02
const char*
?