Converting away from the use of String Variables

@ScruffR, Thanks for the pointer/reference example. I will study it for a little while and see if I can implement it without destroying the existing code.

I feel silly regarding the strftime example since I already use it in several places. I guess for me it’s the case where you sit down to solve a problem and there are at least several ways to code it and you pick one. Did you pick the “best” one? I guess that depends on what metric you’re using to measure “best”. I do like your method better.

Regarding the (const char *) cast for Time.format, is that the standard way to coerce Strings into C-strings?

This is my prefered way.
The alternative would be someString.c_str() which seems a bit clumsy to me but - as the main point for me - would break if I later on decided to change String someString to char someString[] where the type cast will just continue to work without issue (as long noone removes the cast operator overload from String).

@ScruffR Funny…I had been using c_str() myself.

At least I was in the right ballpark.

As I was reworking my Time.format code, I realized I didn’t need the char months[][] array I had been using for the month name. Just added %b into Time.format and voila.

1 Like

@ScruffR Are you a fan of String.reserve()?

I’m not a fan of String at all - I know how to use character arrays and view String as a - excuse the term, entirely personal opinion - lazy cop-out to avoid the need to understand how computers internally work.

But when one “needs” to use String at least invest some time to plan the number of objects needed, how big they will most the time be and how long they should live. And for that String::reserve() may be a handy tool.
Also be aware that any String you just create explicitly or implicitly will be cluttering your heap too.
e.g. this snippet

String emailID = LOCATION + "-" + ((Time.month() < 10) ? "0" + String(Time.month()) : String(Time.month())) +((Time.day() < 10) ? "0" + String(Time.day()) : String(Time.day())) + String(Time.year() - 2000) + "-" + String(emailIDIndex);

produces at least five String objects with a minimum heap allocation of 16 byte each just to immediately dump four of them in the next moment. Not even counting the need for inflation and reallocation of the lvalue object.

2 Likes

@ScruffR I appreciate the honesty…fortunately that line has been replaced with:

snprintf(emailIDBuff, sizeof(emailIDBuff), "%s-%s-%d", (const char *) LOCATION, (const char *) Time.format("%m%d%y"), emailIDIndex++);

LOCATION is currently a string, emailIDIndex is an int.

1 Like

@ScruffR I tried relating your suggestions to my code and the only thing I did was manage to make it so it won’t compile. I understand your explanation where you’re using the param.method() inside the called function, but what about the case where there are no methods, just String data you want to print or manipulate?

For example, here is a snippet of my code showing the called function. The function should take input and write it to a TCP socket and then pause depending on another input variable:

void networkWrite(String line, int waitMillis) 
{
    client.println(line);
    delay(waitMillis);
}

Here is the calling code:

networkWrite("AUTH LOGIN", 75);

I tried adding the reference operator as you suggested, but it causes the compiler to blow chunks:

void networkWrite(String& line, int waitMillis) 
{
    client.println(line);
    delay(waitMillis);
}
"AUTH LOGIN"

is a string literal, not a String

you can change your function to

void networkWrite(const char* line, int waitMillis) 
{
    client.println(line);
    delay(waitMillis);
}

OR you can have two functions (called overloading) with the same name but different parameter types:

void networkWrite(const char* line, int waitMillis) 
{
    client.println(line);
    delay(waitMillis);
}

void networkWrite(String line, int waitMillis) 
{
    client.println(line);
    delay(waitMillis);
}

and the compiler will deduce which function to call based on the objects passed to the function

2 Likes

As @BulldogLowell already mentioned a string literal won't ever be sent as reference.

Just translate the same thing to a numeric constant. How would you send the numeric "literal" 10 into a function by reference?

By ref parameters are meant to create a way to send in a variable so that you can manipulate it inside the function and the manipulation will become evident outside of the function.
For a literal or constant that is by definition not possible nor desirable.

You "asked"

and due to the reasons stated above

has nothing to do with the reference question because for neither of these parameters "sending them by reference" makes no sense at all.

@BulldogLowell, @ScruffR Thanks to you both for the clarification. I guess I’ve gotten paranoid from reading about how bad Strings are in regards to heap fragmentation. I started blindly looking at everywhere I saw the word “String” and how to immediately replace it.