Not quite. If you actually have a String
object, then you can use +
to concatenate the usual suspects via the StringSumHelper
subclass
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
through the magic of implicit conversion
StringSumHelper(const String &s) : String(s) {}
StringSumHelper(const char *p) : String(p) {}
StringSumHelper(char c) : String(c) {}
StringSumHelper(unsigned char num) : String(num) {}
StringSumHelper(int num) : String(num) {}
StringSumHelper(unsigned int num) : String(num) {}
StringSumHelper(long num) : String(num) {}
StringSumHelper(unsigned long num) : String(num) {}
StringSumHelper(float num) : String(num) {}
StringSumHelper(double num) : String(num) {}
So given
float f = 0.0625;
const char *p = "c-string";
String s = "object";
int i = 4;
You actually can't
auto x = f + p; // error: invalid operands of types 'float' and 'const char*' to binary 'operator+'
add a float
to a pointer. But if you start with a String
, you can concat the float
to it (hard-coded to use two decimal places), resulting in another String
; and then repeat with the c-string (or any of those others)
auto y = s + f + p;
auto z = i + p;
Serial.println(y); // object0.06c-string
Serial.println(z); // ring
The last case is where you can get in trouble easily. You can add an integer to a pointer -- i.e. "pointer math" -- but C/C++ will not do any bounds checking, and that might not be what you intended anyway.
If you're just going to print the results once, then I agree that using print
to do each part directly is slightly wordier to type, but better otherwise. It also has the benefit of being able to choose the number of decimal places.
If you want to reuse the resulting string, you may be able to minimize memory issues by reserving the desired space and calling concat
directly, or by using +=
, which does that for you
s.reserve(20);
s += f;
s += p;
s += i;
Serial.println(s); // object0.06c-string4
Serial.println(s.length()); // 19
Very easy to write and read. BTW, the float
-to-String
conversion uses dtostrf
anyway
unsigned char String::concat(float num)
{
char buf[20];
char* string = dtostrf(num, 4, 2, buf);
return concat(string, strlen(string));
}