Double to byte array

I have an existing array of bytes that I transmit between 2 Arduinos using I2C. I need to read the bytes from a double and add them to a specific location in the existing array. At the receiving end I need to convert the bytes back to a double.

Any help would be appreciated, Thanks

byte* doublePtr= (byte*) doubleArray;

Perhaps something like this:

union {
   byte array[4];
   float bigNum;
} myUnion;


// bunch of code...

  myUnion.bigNum = 3.14;

  for (int i = 0; i < sizeof(float); i++) {
      SendSomeplace(myUnion.array[i]);   // Send to wherever
  }

// on the receiving end...

  for (int i = 0; i < sizeof(float); i++) {
      myUnion.array[i] = readBytes();      // Whatever is takes to read the incoming bytes
  }
  float pi = myUnion.bigNum;

That worked. The union command is a simple way to do it. Thanks!

What is this double?

This is a keyword that refers to floating point number.

In UNO Platform:
float x = 11.23; and double x = 11.23; are the same thing. They both store 32-bit value (4-byte) in 4 consecutive memory locations.

In DUE Platform
double x = 11.23; stores 64-bit value (8-byte) into 8 consecutive memory locations

PhoenixFIF:
That worked. The union command is a simple way to do it. Thanks!

it does work but for the record, this is unchartered territory when it comes to the language specification.

The union is only as big as necessary to hold its largest data member. The other data members are allocated in the same bytes as part of that largest member. The details of that allocation are implementation-defined, and it's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union

here you are in a case where the compiler does what you expect - One "right" way to do it is to find the address of your double and read the bytes from there

if you test this code

double value = 123.456;

void setup() {
  Serial.begin(115200);
  byte * valuePtr = (byte *) &value; // we find the address of the first byte

  Serial.print(F("Value uses "));
  Serial.print(sizeof(value));
  Serial.print(F(" bytes in Memory starting at address 0x"));
  Serial.println((uint16_t) valuePtr, HEX);


  for (size_t i = 0; i < sizeof(value); i++) {
    Serial.print(F("Memory address 0x"));
    Serial.print((uint16_t) (valuePtr + i), HEX);
    Serial.print(F("= 0x"));
    Serial.println(*(valuePtr + i), HEX);
  }
}

void loop() {}

on a UNO, you should see this in the Serial monitor (set at 115200 bauds)

[sub][color=purple]Value uses 4 bytes in Memory starting at address 0x100
Memory address 0x100= 0x79
Memory address 0x101= 0xE9
Memory address 0x102= 0xF6
Memory address 0x103= 0x42
[/color][/sub]

which you can verify using an online converter

J-M-L:
it does work but for the record, this is unchartered territory when it comes to the language specification. here you are in a case where the compiler does what you expect - One "right" way to do it is to find the address of your double and read the bytes from there

From K & R (2nd edition):

the results are implementation-dependent if something is stored as one type and extracted as another.

Also, 'union' is a data structure, not a "command".

I'd use memcpy to ensure portability:

memcpy(byteArray, (uint8_t *) &doubleNum, sizeof(double));

gfvalvo:
From K & R (2nd edition):

This is for The C Programming Language... we use a C++ compiler, so behavior "could" be different :slight_smile:
also the second edition dates from 1988, we are 30 years later - the specs have evolved.

gfvalvo:
Also, 'union' is a data structure, not a "command".

technically I'd argue a union is a user defined data type rather than structure

:grin: :smiling_imp: :grin:

J-M-L:
also the second edition dates from 1988, we are 30 years later - the specs have evolved.

Not denying I'm old 8)
Learned 'C' in college circa 1983 -- from K & R FIRST Edition!

gfvalvo:
Not denying I'm old 8)
Learned 'C' in college circa 1983 -- from K & R FIRST Edition!

same here :slight_smile:

// I have an existing array of bytes that I transmit between 2 Arduinos using I2C.
byte ArrayOfBytes[193];

// I need to read the bytes from a double and add them to a specific location in the existing array.
const int SpecificLocation = 37;

double foo = 123.456;

void loop1()
{
  for (size_t i = 0; i < sizeof foo; i++)
    ArrayOfBytes[SpecificLocation + i] = ((byte *)&foo)[i];
}
// At the receiving end I need to convert the bytes back to a double.
void loop2()
{
  byte ReceivedArrayOfBytes[193];
  const int SpecificLocation = 37;
  double foo;
  for (size_t i = 0; i < sizeof foo; i++)
    ((byte *)&foo)[i] = ReceivedArrayOfBytes[SpecificLocation + i];
}

PS: I learned C in college, too. I graduated in 1980.

1 Like

I was only taught a bit of pascal and 6809 assembly :wink: And Nassi–Shneiderman diagrams.

johnwasser:
PS: I learned C in college, too. I graduated in 1980.

I'm wearing shoes older than that.

@J-M-L: Yep, it is implementation specific, but if the code on both ends is compiled with the same compiler, I've yet to find an instance where it didn't work.

econjack:
@J-M-L: Yep, it is implementation specific, but if the code on both ends is compiled with the same compiler, I've yet to find an instance where it didn't work.

Yes GCC for simple union like this is pretty predictable as there is not much optimization that can happen but you could imagine that the compiler caches some value in registers and when you try to access the bytes another way then the data has not been sync-ed yet in the union data as the compiler could see that as a distinct variable access (and of course you have major caveat about endian-ness across systems)

Also if you have code like this

 union {
   uint32_t val;
   char code;
} var;

you can't be certain which byte will be used to store the code, the compiler in certain architecture could make decisions based on where in memory the variable would be

but overall yes, it's OK, just remember you are using and relying on a non standard compiler extension when it works