I'm trying to use the F() FlashStringHelper macro to save some ram. I can get it to work with a single string, but can't figure out the syntax to use it for more than one.
Serial.println (F("I am here")); compiles & works! Serial.println (F("MyVar =") + String(myVar) + F(" and YourVar =") + String(yourVar)); gives a bunch of errors including:
error: conversion from 'const __FlashStringHelper*' to 'const StringSumHelper' is ambiguous
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:201: note: candidates are: StringSumHelper::StringSumHelper(long unsigned int)
So what would be the correct syntax to make my second example compile/work?
Yeah, I could do: Serial.print (F("MyVar = ")); Serial.print (myVar); Serial.print (F(" and YourVar = ")); Serial.println (yourVar);
but I was hoping not to turn 1 line into 4!
What a load of shit. NO ONE should be encouraging the use of the resource-wasting String class. There is NOTHING to be gained from using one print() call vs. using more than one. NOTHING.
PaulS, not strictly true. For example, const String& type of a function parameter can serve as proxy for a few different argument types, including const _FlashStringHelper type that saves precious memory by storing strings in PROGMEM. And it is done transparently without introducing any unnecessary boilerplate code.
Regarding the OP's question, it can be easily done by wrapping F() calls into String() instead of char[] themselves, like so:
In addition, you could easily overload << operator as described here to concatenate these directly without having to wrap them into String, while also making your code more succinct:
Serial << F("myIntVar =") << myIntVar << F(" and myStrVar =") << myStrVar << '\n';
PaulS, I already looked at memory consumption, and it doesn't add anything at all. String(const __FlashStringHelper*) constructor doesn't actually convert them into SRAM String, just stores the pointer. So it is exactly the same as if you did a single String.print() call. The << operator also doesn't consume any resources as it is translated to those Print calls by compiler. Please try
Memory consumption stays exactly the same at 206 bytes in my code (I have other pieces there as well, so you may get a different value). Moreover, if I use
Serial.println(i);
as the last call in the first scenario, memory consumption jumps to 222 bytes (!), even though println() is supposed to add only one extra '\r' character at the end.
in my example from above (only a minor increase in flash use for my suggested solution, but that is a cheap price to pay given that there's much more flash than RAM).
Also, I don't see how that is different from individual calls to String.print(), given that the overloaded operator is translated to essentially the same code. Perhaps you're talking about something else? Like __FlashStringHelper* vs String& ? In addition, I don't think it uses copy (which would lead to extra heap) - please take a look at size_t Print::print(const __FlashStringHelper *ifsh) in Print.cpp, it directly reads bytes from PROGMEM and streams them to the output from what I understand.
{
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
else invalidate();
return *this;
}
So, does it make a copy to SRAM or not?
Ok, looks like I was wrong in this case, though I was leaning more toward the second solution involving <<. My values comparing the two are for that case only. Though could the current implementation involving String translation be improved by not having to copy the data but rather read it directly when String content is requested? I thought that was the whole point of storing things in PROGMEM..[/code]
Coding Badly, sorry for miscommunication - I was referring to '<<' solution all the way when I was talking about them being identical. oqibidipo' examples make it obvious that the strings are copied. Otherwise yes, either direct .print of one variable at a time (or its << shorthand one-liner) make it most efficient and RAM-saving wise. I would argue though that it all depends on exact use case and whether code readability/compactness is worth a trade-off with saving RAM.
I missed reply #14. Sorry about that. Probably a side effect of purging @zoomkat's off-topic trolling.
So...
denvlad:
For example, const String& type of a function parameter can serve as proxy for a few different argument types, including const _FlashStringHelper...
Yes, now I see that's not correct. Again, no need to wrap in String() though if you could use a '<<' shorthand in this particular use case. Of course, one will need to overload their functions with a separate case for (const __FlashStringHelper*) if they want to use both SRAM and PROGMEM 'strings' with a custom function.
Yep, thanks for the explanation btw. Hopefully our posts will help others who learn this stuff in the future.