Confusion with strings and string size in C++

I hope im right here.
I have a little program for the ESP8266
//platformio.ini

[env:esp12e]
monitor_speed = 115200
platform = espressif8266
board = esp12e
framework = arduino

and I need to use a string variable

string hello = "Hello";

but I get an error error: ‘string’ does not name a type
searching I found different answers
some say if i include #include <Arduino.h> what I dis it must works as Arduinio,h handles it
other say i have to include
other say I have to include <string.h>
other say I have to include <String.h> the only one that does work.
Can anybody clear that up.

Then i like to get the string size.

String myStr "Hello";
uint8_t myStrLen;
char sl[5];

myStrLen = sizeof(myStr); 
Serial.Println(itoa(myStrLen,sl,10)); gives me 12
Search I found the alternatives 
myStrLen = myStr.size; gives error
myStrLen = myStr.length; gives error

Can some exlain it

Thanks Rainer

1 Like

There are multiple ways to do “strings” in C++ programs and especially in the Arduino environment.

First of all, the correct and most common way: In Arduino firmwares, use the Arduino-provided standard String class. This class is automatically available to you when you #include <Arduino.h>. The class is declared more specifically in WString.h (<-- for Arduino-ESP8266).

An example usage would be

//#include <Arduino.h> above..

String stringOne = "Hello String";   // using a constant String
stringOne += "ABC"; //dynamic string concat
unsigned len = stringOne.length();  // get length

Correct, because those are no such member variables exist. The Arduino String class has the length() method though, thus you must call it as myStrLen = myStr.length();.

Be aware that String uses dynamic memory, which is not too good for small-memory devices. There are blogpost about The Evils of Arduino Strings and Are Strings really that Evil? about it. Though for an ESP8266, it doesn’t really matter.

This is wrong. sizeof() with the String myStr variable gives you the size of an instance of a String class. This will basically the sum of all sizes of the internal variables of the class. This will not represent the length of the string it is holding internally (to which it has a pointer). You can only sensible use sizeof on character arrays of compile-time known length in the context of strings.

So

char myStr[] = "Hello";
unsigned len = sizeof(myStr);

will have len = 6. Mind that a C-string contains a NUL terminator (\0) character at the end, which counts into the sizeof the string. strlen(myStr) would return 5.

But we’re slightly jumping ahead.

What you’re attempting to do here is to use the string class of the standard C++ library. This class is in the std namespace and avaible via the string header, so you need to do #include <string>. Not #include <string.h>, which will give you the C-string functions, instead of the C++ ones.

To access the class you can do

#include <string>

void func() {
   std::string myString = "ABC";
}

or, by using a using namespace declaration you can import all of std’s classes into the global namespace. Though some consider this bad practice (namespace polution).

#include <string>
using namespace std;

void func() {
   string myString = "ABC";
}

You can find a list of functions that work on std::string in the documentation.

Note that the Arduino String class, which most libraries use if it comes to strings, is not interchangably usable with std::string and vice versa. These are different classes, after all. You would need to convert between them by e.g. first converting an Arduino string to a pure const char* via .c_str() and using that in the constructor of a std::string, or vice-versa. (The std::string also has the c_str() function).

And finally, there are pure C strings, aka an array of characters or a pointer to them. In C++ you can include the C functions with either

#include <string.h>

or

#include <cstring>

See documentation here.

You of course don’t need to include any headers to get the basic “string type”, char [] or char*, since it is a fundamental C/C++ type.

Usage of C-strings would e.g. be

#include <string.h>

void gets_c_string(const char* szString);

void test() {
    //initialize string
    char myString[] = "Hello, world!";
    //copy into another character buffer
    char myBuffer[32] = {0}; 
    strncpy(myBuffer, myString, sizeof(myString)); //prefer strncpy over strcpy
    gets_c_string(myString);
}

void gets_c_string(const char* szString) {
   unsigned len = strlen(szString); 
   //...
}

You are free to use whatever string type you want in your program, and each of them has certain advantages and disadvantages. With C-strings you can very low-level control the strings and their sizes, wheres with String and std::string memory management is done on the heap and automatically for you, in a way you might or might not want (e.g., over-allocating storage space on string concat).

If you just need to pass some constant strings around, you should be using C-strings (const char*/char[]). If you need to perform operations like dynamic string concatination, easy searching of strings, string replacement etc., I would suggest the Arduino String class. Only if there’s really some functionality that isn’t in Arduino String, or when programming for platforms that don’t have an Arduino String, I would suggest std::string.

1 Like

Thank you for that excellent comment
Rainer