This header is for functions regarding C-style strings, which are const char*, pointing to the start of memory where the character data is store (until a 0 byte / \0 is encountered). This header is also known a #include <cstring> in C++.
I think here you’re refering to the std::string from the C++ standard library. That’s included via #include <string>. Not string.h. Also, if you don’t do a using namespace std;, you have to write std::string instead of string. It is however considered not good practice to do that.
But, there’s also another dimension to it: std::string from the C++ standard library are convenient, since you can do addition and resizing and finding substrings etc directly on there, but they work by allocating memory on the heap, which is generally bad for small embedded devices. The Arduino String class works in approximately the same way, and thus also considered bad. (see this and this article). You may also find the first few paragaphs of this article interesting.
So I’d highly recommand to stay with C-style strings for the embedded world. For your code that would mean that you write normal strings into variables of type const char* or const char variablename.
The given str should be a const char*, since you probably do not modify the string inside the function, thus it stays constant. Same goes for executeCommand(). Setting a paramter to const will enable the compiler to do some optimizations, like putting a string or variables purely in Flash instead of RAM (and flash for init value).
Of course, you may still want to experiment with std::string. One would expect to be able to write
As you can pass a constant standard-string reference. Constant because again the string you’re passing shouldn’t need to be modified during sending. And a refernce because you don’t want to pass the std::string object by value – a refernce is a pointer under the hood here for all intents and purposes, but prettier.
|-- <ArduinoSTL> 1.1.0
Building in release mode
Checking size .pio\build\ATmega4809\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [ ] 0.2% (used 10 bytes from 6144 bytes)
Flash: [ ] 2.6% (used 1278 bytes from 49152 bytes)
=========================== [SUCCESS] Took 1.74 seconds ===========================
Note that this also uses a neat trick: Although we have declared framework = arduino, and the Arduino framework will be compiled a part of it is needed by ArduinoSTL, we were are still able to override the main() function. Thus we bypass the Arduino entry point and the linker will throw out most of the Arduino framework that is not used.
If I added
on top and implemented main() as setup() and an empty loop, the program would grow to
RAM: [ ] 0.2% (used 14 bytes from 6144 bytes)
Flash: [ ] 3.1% (used 1536 bytes from 49152 bytes)
=========================== [SUCCESS] Took 2.13 seconds ===========================
so we are able to throw quite a bit out if we abuse ArduinoSTL for just the string header while ignoring most of Arduino.
But yeah, this was a rather long expedition. Main take-aways are
if you want to be as memory-efficient as possible, only use C strings, aka const char* and string.h
using C++ std::string and the string header in C++ is not possible by default with AVR-GCC
but, can be supplemented by a library, for both Arduino cases and baremetal cases (if we accept that a tiny bit of Arduino code is in there as ArduinoSTL’s dependency)
if you want to stay 100% pure baremetal though, then either use C-strings or copy just the std::string implementation from ArduinoSTL in your project
know the dangers of heap-based string implementations like String and std::string
they still have their usefullness though, and if correctly used can also be efficient
thanks for this hugely comprehensive reply Max, much appreciated. I walked into arduino coding a few years ago and wrote my shaft encoder project in a few days. I chose it as a baremetal project as I knew the coding requirements and the project has some good requirements such as serial exchanges between mcus and the use of interrupts for the encoder changes. The baremetal stuff is an enjoyable excursion, but much harder as it’s closer to hardware (as the name implies…). I think it will become easier as I get to know the hardware more.
Thanks also for picking up on const correctness, I read the link and it makes sense to be const correct from the outset.
There are some conflicting resources out there (some of which seem credible) and that’s why I ended up posting my string problem.
I’ll stick with C strings, I also looked in the stdlib.h and there are functions to convert string to double and double to string, which is all I need re strings in this project.