When Writing Library, return String or return char *

I asked this question in another site but did not get any response so I am trying my luck here.

I am trying to write my own Arduino library and I would like to make it useful not just for ESP32/ESP8266 boards but also with Arduino boards.

I have created my header file like this
test.h

#ifndef TEST
#define TEST
#include "Arduino.h"
  
#define MAX_STRING_LEN 50
  
class MyClass{
    private:
  
    public:
        String getString();
        char * getCharPointer();
        char * getAnotherCharPointer();
};
  
#endif

and my
test.cpp

#include "test.h"
    
    
static char buffer[MAX_STRING_LEN+1];
  
String MyClass::getString(){
  // Sample REST API call
  String testString = String("{\"test:\" \"hello String json\"}");
  
  return testString;
}
  
char * MyClass::getCharPointer(){
  // Sample REST API call
  const char * sample_json = "{\"test:\" \"hello Char Pointer json\"}";
  strcpy(buffer, sample_json);
  return buffer;
}
  
char * MyClass::getAnotherCharPointer(){
  // Sample REST API call
  const char * sample_json = "{\"test:\" \"hello Another Char Pointer json\"}";
  strcpy(buffer, sample_json);
  return buffer;
}

My test file main.cpp
main.cpp

#include <Arduino.h>
#include "test.h"
  
MyClass myClass;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  
  Serial.println(myClass.getString());
  Serial.println(myClass.getCharPointer());
  Serial.println(myClass.getAnotherCharPointer());
}
  
void loop() {
  // put your main code here, to run repeatedly:
}

Result is ok

{"test:" "hello String json"}
{"test:" "hello Char Pointer json"}
{"test:" "hello Another Char Pointer json"}

I have these doubts that I would like to ask for suggestions.

  1. Is returning the String class in Header files, not a good idea? For ESP32/ESP8266 they are okay as they have big memory but for Arduino Uno boards I see a lot of discussions about not using String because it is bad and causes memory fragmentation etc.

  2. Is returning char * the safest way to make it compatible and useful to all MCU boards?

  3. Next question in char pointer, I often see this pattern done when returning char pointers like in this Time.cpp wherein a static buffer is used and defined at the implementation file (test.cpp) and all functions(getCharPointer, getAnotherCharPointer) that needs to return a char pointer just manipulates the static char buffer by using strcpy. Is this the proper way to go in Arduino programming?

Can somebody please clear my doubts? Thank you.

answer to 1 is does throwing more than you have to on an AVR's return stack seem like a good idea? You can do it, but not very far.

answer to 2. You can overload the class, the compiler only includes what's used in the hex.

answer to 3. Make a class that you point to and init, point it at the buffer. When you use default SD it has a 512 byte buffer you can work from. 40 years ago I did the same with drive buffers on S-100 work machines and SD runs the same basic way.

The String class wastes cycles and RAM for only convenience with guardrails.
C strings and pointers are next to the metal and far, far more flexible.

There's people here who can show you how to task on a single thread with No OS.

to 2) : virtual class methods take space in SRAM for the 'virtual table' and are not optimized away with gcc even if not used

➜ return a const char * (if you don't want the caller to mess around with your buffer). If the caller wants a String, they can always do so by storing the returned value into a String instance.

char buf[] = "Hello World";

const char * getCharPointer() {
  return buf;
}

void setup() {
  Serial.begin(115200); Serial.println();
  String s = getCharPointer();
  Serial.println(s);
}

void loop() {}

note that there is a difference between the String version and the char * version. In the String version you always return a different String (copy). In the char * version, you always return the same pointer to the same buffer. So the way this needs to be coded depends on your needs too

More reason to stick with C which is looser with pointers too.

You can also pass the address of your buffer or a pointer to your buffer to your function as an argument.
You can add the buffer size as well so the function will not write outside the buffer.
You will not need a return value then (as the return value is in the buffer argument).
Instead you can return a bool to confirm that the function succeeded.
This way you will not depend on a global buffer. You can also have multiple buffers if needed.
Functions of the string manipulation library often use this method.

maybe ask yourself why strcpy doesn't return a pointer but requires you to provide a buffer

Note that "getCharPointer()" and "getAnotherCharPointer()" both return the same pointer (buffer).

  char *first = myClass.getCharPointer();
  char * second = myClass.getAnotherCharPointer();
  Serial.println(first);
  Serial.println(second);

will result in:

{"test:" "hello Another Char Pointer json"}
{"test:" "hello Another Char Pointer json"}
1 Like

why returning pointer to a global buffer if one can access it directly?

as for writing another bad library, I suggest you look up how good libraries are written and follow the example

Maybe return a status byte as to any error condition if possible?

It might be to an address within the buffer.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.