when i try to use a union in order to link a float to a 4 bytes array.
union btf
{
byte b[4];
float v;
} ;
union btf message;
message.v = 823.5;
i have the error code : "Compilation error: 'message' does not name a type"
i tried to declare the union with typedef by all the ways i know then declare my union btf (for byte to float). But i get this error anyway. Does anyone have a solution ? Texte préformaté
This is not allowed. Reading from an inactive union member invokes undefined behavior.
To convert between a float and the bytes that represent it, use memcpy instead, or use a cast to a pointer to character type. For a more detailed explanation and valid alternatives, see:
Casting a pointer to any object to a pointer to character type is allowed, this use case is covered explicitly in the page I linked to in the previous post.
byte myData[sizeof(float)];
float num = 823.5;
memcpy(&myData, &num, sizeof myData);
for (int i = sizeof(float)-1; i >= 0; i--)
{
byte y = myData[i];
if (y < 0x10)
{
Serial.print('0'); //show leading zero
}
Serial.print(myData[i], HEX); //shows: 444DE000
}
That's in no way better than the union, only takes more time. Consider memcpy(&btf.v, btf.b, sizeof(btf.v));
satisfies the union restrictions, takes time unless optimized away, and afterwards b and v cannot be different, so the "last active" claim is irrelevant.
So what's the C++ union mutilation worth after all?
Are you trying to put the executable code "message.v = 823.5" outside a function? That would explain the error message. Only declarations are allowed outside of functions. Declarations start with a data type and 'message' is a variable, not a data type.
@johnwasser, that is a good observation. That would definitely cause that error. If attempting to initialize as global then something like this would work:
union btf
{
byte b[4];
float v;
} ;
union btf message = { .v = 823.5 };
No, it is not. The only advantage is that almost all other ways are forbidden in C++. Hacks had to be introduced to overcome the drawbacks of these bans. This can be called "better" only with regards to the C++ specs and without knowledge of the well working C style unions.
This is not allowed either (i.e., it causes undefined behavior). The source and destination cannot overlap. Use memmove instead. Or just scrap the union altogether and use something like @GolamMostafa's code, or just cast to char *, depending on exactly what you need to do.
C unions weren't designed for type punning. Unions are meant as algebraic sum types, hence the name “union”. Implementing sum types to have the variants occupy the same memory is a logical implementation choice, not the union's purpose.
In the earliest versions of the C standard, the behavior of accessing “inactive” members of a union was left unspecified (see e.g. §6.3.2.3 Structure and union members of the C89 standard). Early (simple) compilers allowed type punning because of the straightforward implementations, but it was not originally intended.
It was only in 2004, in this defect report to the C99 standard, that type punning was specified in C.
C++ branched off way before 2004, so there was no reason to suddenly allow this unnecessary abuse of unions.
If your goal is to reinterpret the memory representation of an object as an array of bytes, the obvious choices are (and have been for as long as they've existed) memcpy, bit_cast and reinterpret_cast, which explicitly deal with memory representation/interpretation.
Using a union for such an unrelated purpose only appears logical to C programmers who learned the union hack from other C programmers before them.