0

I have a union (ValueDefinition) with pointers of different datatypes in it and functions to create it. With String it works fine:

ValueDefinition CreateValDefString(String value){
        ValueDefinition valDef = {.ValueString = new String(value)};
        return valDef;
    }

But when I do the same with e.g. uint8_t it compiles, but at runtime I get this error:

[E][WString.cpp:185] changeBuffer(): realloc failed! Buffer unchanged

That's the code for the uint8_t:

ValueDefinition CreateValDefUint8(uint8_t value){
    ValueDefinition valDef = {.ValueUInt8 = new uint8_t(value)};
    return valDef;
}

What am I doing wrong? I tried it without "new" and with malloc, but I still get the same error.

Edit: As requested, the definition of ValueDefinition:

 union ValueDefinition{
     bool* ValueBool;
     int8_t* ValueInt8;
     int16_t* ValueInt16;
     int32_t* ValueInt32;
     uint8_t* ValueUInt8;
     uint16_t* ValueUInt16;
     uint32_t* ValueUInt32;
     float* ValueFloat;     
     ulong* ValueULong;
     String* ValueString;
 };
Mr.Sheep
  • 311
  • 3
  • 16

1 Answers1

1

In your code, it looks like C++ is throwing an error to a function to create a WString instead of uint8_t, hence the stacktrace in a completely separate header. Searching the source code in the repository for arduino shows that there is an error in WString.cpp here, which is what your compiler's detecting.

The github users suggest using a different string library, and since the bug hasn't been fixed you'll have to change, probably to the standard string library defined by C++ and not arduino. As the users have stated on github, arduino strings are notoriously unreliable.

In other words, this error has nothing to do with your code, but a question that I'd like to ask is "Why use unions in C++?" If you want to define a generic type just use templates, ex:

 template<class T>

 class ValueDefinition<T> {
 private:
     T typeDat;
 public:
     Valuedefinition(T t);
     /* etc. */
 }

Unions were made so that C could have a way to use generic typing by having several types share the data in the union. Another common use is taking advantage of the data types using the same memory to find the underlying binary of more complex types, such as using individual uint8_t values underlying a long long to find the value of its bits or using an int to get the binary value of a float, ex:

union foo {
   uint8_t bits[4]; /* Represent the bits of 'data' */

   long long int data;
}

union foo myLong = {.data = 12378591249169278l};
printf("%d\n", myLong.bits[0]); // Returns the value of the high bit of myLong

However note that this is undefined behavior because unions are usually padded and architectures use a different form of endianess. Whatever you're doing, if you're using C++ there's a better way to implement your solution than using unions, since this was a feature meant for a language that had no generic typing in order to save memory.

Edit: Initialize ValueDefinition using C's malloc like so:

union ValueDefinition *value = malloc(sizeof(union ValueDefinition));
value->ValueUInt8 = malloc(sizeof(uint8_t));
/* more code */

Or with C++'s new:

union ValueDefinition *value = new ValueDefinition();
value->ValueUInt8 = new uint8_t(/* Some number */);
/* more code */
Nolan Faught
  • 406
  • 3
  • 13