How to obtain the size of a struct with an Arduino String as one of its member

Hello.
I am trying to determine the size of a struct like this:

struct SessionInfo_t
{
    uint32_t _ip = 0;
    eth_addr _mac{};
    String _userID;

    operator bool() const { return _userID.length(); }

    SessionInfo_t(const uint32_t &ip, const eth_addr mac, const String &id) : _ip(ip), _mac(mac), _userID(id)
    {

#if defined(DEBUG_ACTIVE)

        Serial.println("Session created");
        Serial.printf("IP: %u\n", _ip);
        Serial.print("MAC: ");
        for (auto &&i : _mac.addr)
            Serial.printf("%u:", i);
        Serial.printf("\nID: %s\n\n", _userID);

#endif // DEBUG_ACTIVE
    }

    SessionInfo_t(){};
#if defined(DEBUG_ACTIVE)

    ~SessionInfo_t()
    {
        Serial.println("Session removed:");
        Serial.printf("IP: %u\n", _ip);
        Serial.print("MAC: ");
        for (auto &&i : _mac.addr)
            Serial.printf("%u:", i);
        Serial.printf("\nID: %s\n\n", _userID);
    }

#endif // DEBUG_ACTIVE
} session;

At first sight, I was planning to use sizeof(SessionInfo_t) or sizeof(session).
However, I found that the size of Arduino String (i.e., _userID) is variable, as it is dynamically allocated at runtime. Therefore, it may not be possible for the sizeof() operator to evaluate the size of the String at runtime.
The size of the struct instance would be used to write its raw data to a file using the SD.write(data, buf) function of the SD class, as suggested in this post.

Does anyone here a way of determining the exact size of each instance of the struct?

Thanks in advance.

p.s. To provide more context of what this is for, feel free could visit my GitHub repo.

You can't store a String type structure field to the file with raw write() function. The reason is the same as why you can't use the sizeof() function for determine the structure size - because the String use the dynamic allocation for store its contents.

String buffer, consider.

I make this structure

const int payloadSize = 100;
struct stu_message
{
  char payload [payloadSize] = {'\0'};
  String topic ;
} x_message;

then in setup I do this code

voiding setup()
{
  x_message.topic.reserve(100);

}

Now I have a String buffer of 100 characters, so I know length.

to put things into String buffer use

      MQTTinfo.concat( String(kph, 2) );
      MQTTinfo.concat( ",");
      MQTTinfo.concat( windDirection );
      MQTTinfo.concat( ",");
      MQTTinfo.concat( String(rain, 2) );

the concat() thingy

do not use

MQTTinfo="wef eiorfvnoiefbvnoi"

to clear the string buffer.

MQTTinfo='"";

Just some proper management of the String is all that's needed.

I can also do int sdfsdf = MQTTinfo.length().

Is this the also the case if I substitute String with std::string?

Your structure should contains a srting with FIXED size to do what you want

struct SessionInfo_t
{
    uint32_t _ip = 0;
    eth_addr _mac{};
    char  _userID[30];
}

Interesting solution...
But if I am to read the date from file, I have to parse the string using , as delimiter using String::subString() paired with String::indexOf(), then assigning the results to corresponding member variables. This could also be done using JSON much easier.
I planned to write raw date and do a reinterpret_cast<SessionInfo_t> for continence and efficiency. So, serialising the data when writing and then parsing it for reading would not be as optimal, I suppose.
Your suggestion is rather inspiring, though.

Is it an option for me to calculate its size 'manually':

auto size_of_struct = sizeof(_ip)+sizeof(_mac)+(sizeof(_userID.length()/_userID[0]));

Although I have heard that there are 'padding bytes', whatever they are...

And, is there a way of getting the size of variables at runtime?

not a

(sizeof(_userID.length()/_userID[0]),

but just

sizeof(_userID),

if you using the fixed length string, it size in the runtime will be the same as on compiling

What about dynamic ones?

do not use automatic dynamic types (as a String) if you need to know it size. Use predefined size Strings as in the @Idahowalker example

Will this method be viable and robust? Will it be affected by compiler optimisations and/or padding bytes?

I believe that this expression is not correct. See my post #9.

Is the corrected one valid for my purpose?

You may also put a pointer to your String in your struct. Then the size of your struct will be constant and you do not need to reserve 100 characters just to be sure...
This might get important if you make an array of structs.

Again, if you do not use a dynamic storage types you can just take the structure size like sizeof(SessionInfo_t). It will be correct considering optimisation and padding.
Regarding dynamic types - I don't have a correct answer.

So I use:

auto string_ptr = std::make_unique<String>("Some text for string");

Like this?

Although this does give me constant size, it cannot be used to write to file, as the pointer is just an address represented by an integer rather than a string.
When the write-to-file operation is done, the struct will be out of scope and freed. So, the address extracted from the file will no longer be valid for retrieving the targeted String.

It does seem like a reasonable idea to use static allocation inthis case.