I'm working on a project where I need to create a JSON to send back state of an object. I created the code to achieve it and all works fine, but I used this to declare the JSON fields:
static const String JSON_FIELD_A;
then in the .cpp file
const String MyClass::JSON_FIELD_A = "field_a";
In this way I can use that in several point inside my class (eg. to create and parse JSON) without needs to write the field name each time which may cause inconsistency after a refactoring.
I'm not sure about this way anyway... is there a more efficient way to achieve that? Using #define may be a solution?
2 Answers 2
The "traditional" way is to use PROGMEM
and use const char *
strings.
I don't use the "traditional" way. Instead I use some "helper" classes and macros that WString.h provides.
This does mean, though, due to limitations in C++, that you have to create your string constants in two stages.
First is to define your variables:
const __FlashStringHelper *stringOne;
const __FlashStringHelper *stringTwo;
Then you need to assign the actual strings to those variables within a function. This could be in setup()
, but I prefer to define an initializeStrings()
function that setup()
calls:
void initializeStrings() {
stringOne = F("This is the first string")
stringTwo = F("This is the second string");
}
void setup() {
initializeStrings();
}
You can then pass these objects (they're not really objects, it's all just some magic casting done by the compiler) as parameters to other functions using const __FlashStringHelper *
as the type. They can also be passed directly to any of the .print()
and .println()
functions provided by the Print
class (which all Stream
objects ultimately inherit).
If you want to use the standard C string library functions _P
variants for manipulating the strings (concatenating them to other strings, for instance), you can simply cast them to PGM_P
:
char temp[50];
strcpy_P(temp, (PGM_P)stringOne);
strcat_P(temp, (PGM_P)stringTwo);
Another alternative to all that is to use precompiler macros.
#define STRING_ONE F("This is the first string");
#define STRING_TWO F("This is the second string");
Again, you can cast those to PGM_P
to use the _P
variants of the standard C string library functions, and pass them directly to print
functions, since they are replaced verbatim as F("This is the first string")
, and F()
does a reinterpret-cast to const __FlashStringHelper *
.
-
it is all `const char* and we must track which one is in flash and which in RAM and use the right functions. __FlashStringHelper is a trick to match the flash variants. but a trick not recognized by _P functions. so we need to cast it back to const char*. but I doubt a beginner can understand this2018年07月31日 11:29:18 +00:00Commented Jul 31, 2018 at 11:29
-
@Juraj Ah... the complexities of Harvard architecture. It's such a joy. One of the many reasons I never use AVR chips :)Majenko– Majenko2018年07月31日 11:31:09 +00:00Commented Jul 31, 2018 at 11:31
const String
does make nothing constant. You create an object, which can't be reassigned, but all methods work. Because it handles the characters inside and the const declaration doesn't change it. You can delete the content, change the content, append the content of the String object.
You should use const char*
or const char[]
. It is an c-string and the compiler checks if it is handled as a constant at gives at least a warning if not.
To save RAM the const char[]
should be declared as PROGMEM. At runtime then this string isn't copied into RAM. You can use it with functions with _P postfix or copy it temporally to RAM.
Example from my project:
global char array with PROGMEM
const char data[] PROGMEM = "{\"suspension_time_seconds\":10800}";
use in a function
client.print(F("Content-Length: "));
client.println(strlen_P(data));
char buff[64];
strcpy_P(buff, data);
client.print(buff);
-
You don't need to copy a PROGMEM string into RAM just to "print" it. Just cast it to
const __FlashStringHelper *
:client.print((const __FlashStringHelper *)data);
Majenko– Majenko2018年07月31日 10:52:52 +00:00Commented Jul 31, 2018 at 10:52 -
I know. Wrong example with print. It should be some function that has not a variant for progmem.2018年07月31日 11:19:33 +00:00Commented Jul 31, 2018 at 11:19
Explore related questions
See similar questions with these tags.
F()
macro, and the__FlashStringHelper
stub class. As well as the_P
variants of the standard string library functions.