0

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
  • 1
    Doesn't this method have an overload that accepts a const char*? Feb 21 at 19:30
3

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.

9
  • I guess what he really needs is not a compile-time version of snprintf (that would be quite useless), but a myMethod that takes a const char*.
    – PMF
    Feb 21 at 20:25
  • I can absolutely see uses for compile-time string formatting. Though yes, it probably will come down to the latter.
    – timemage
    Feb 21 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 like snprintf(F("..."), 30, F("Result is %d"), 60); cannot work, because the result of snprintf can certainly not be in flash.
    – PMF
    Feb 21 at 20:31
  • 2
    You could, but you needn't. There already exists an snprintf_P variant capable of taking the format string from PROGMEM. You'd probably use PSTR there instead though. I'm not seeing the relevance of this though.
    – timemage
    Feb 21 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
    Feb 21 at 21:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.