Problem with the use of union

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é

Not sure, but I think this line should be
btf message;

BTW, this is the French part of the forum, so you should speak French here or switch to the mainstream forum

Or you can do it like so:


union btf
{
   byte b[4];
   float v;
} message;

void setup()
{
   Serial.begin(115200);
   message.v = 823.5;
   Serial.print("the value of message.v = ");
   Serial.println(message.v);
}

void loop()
{   
}

This, I believe, is type punning and is discouraged from what I have read. And the code is not portable as in some processors floats are not 4 bytes.

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:

Don't use unions or pointer casts for type punning

What then is the correct way to e.g. transmit a float over a byte stream?

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
  }

Nothing is wrong with that code, you print from active member

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?

It is much better than the union, because memcpy is the only officially supported way, and type punning using unions is disallowed.

It doesn't. As also mentioned in the aforementioned page, no actual copy is made:

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.

What would be your comment about the following approach?

  byte myData[4];
  float num = 823.5;
  unsigned long *ptr;
  ptr = (unsigned long*) &num;
  unsigned long m = *ptr;
  Serial.println(m, HEX); //444DE000

@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.

It works just fine, though, on Arduino using gcc. Been using it for years to do exactly what the OP wants to do.

Sometimes, risky behavior works out well.

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.

With respect to languages like C or C++, that's a ridiculous stance: Undefined behavior - cppreference.com

I was pretty sure that you would not approve :wink:

So your code works until it doesn’t because someone somewhere updated compiler, what a wonderful world