1

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?

  • This looks reasonable – esoterik Jul 30 '18 at 19:12
  • 2
    You should look at the F() macro, and the __FlashStringHelper stub class. As well as the _P variants of the standard string library functions. – Majenko Jul 30 '18 at 21:17
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 this – Juraj Jul 31 '18 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 Jul 31 '18 at 11:31
1

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 Jul 31 '18 at 10:52
  • I know. Wrong example with print. It should be some function that has not a variant for progmem. – Juraj Jul 31 '18 at 11:19

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.