1510543923 is stored as: 01011010 00001001 00010010 00110011
This is known as "big endian", or "MSB first", because the most significant byte (MSB, here 01011010) comes first.
I recommend against this order. If you can, swap all the bytes and store the value LSB first, i.e. with the least significant byte first, and the most significant byte last. This will make your life easier since it's the order used internally in the Arduino. If you can go little endian, then you will be able to read the data straight into the required variable, with no conversion needed, as in:
i2c_eeprom_read_buffer(0x50, 25, (byte *) &j, sizeof j);
and it will work identically with any data type.
If you cannot choose the byte order (maybe you cannot control what is inside the EEPROM), then you will have to reverse all the bytes. You can do this either with bit shifts or by explicitly moving bytes.
bytes[1] << 16
This will not work. Per the rules of the C++ language, bytes[1]
is
implicitly promoted to int
type before the shift, then it is shifted
as an int
. But on your Arduino an int
is 16-bits long, thus by
shifting it 16 positions you are dropping off all of the bits.
Actually, this is even worse: you are invoking what is known as
undefined behavior, meaning that it is considered nonsense and the
compiler is free to interpret however it wants.
To do this properly, you first have to explicitly cast bytes[i]
to
unsigned long
. It has to be unsigned because changing the sign bit on
a long
by bit shifting is also undefined behavior. Thus, the proper
way of reconstructing the number via bit shifts is:
long j = ((unsigned long) bytes[3] << 0)
| ((unsigned long) bytes[2] << 8)
| ((unsigned long) bytes[1] << 16)
| ((unsigned long) bytes[0] << 24);
This is portable (it should also work on big-endian architectures) but only works with integral types, not with floats.
MyFor reconstructing a float, my preferred option would be to use aunion
, in order to access the
bytes bytes of the variable explicitly. Then you
you just have to write those
bytes reversed relative to copy the bytes from the buffer to the union
in
reverse order:
union { float f; byte b[4]; } data;
data.b[0] = bytes[3];
data.b[1] = bytes[2];
data.b[2] = bytes[1];
data.b[3] = bytes[0];
float x = data.f;
One nice thing about this approach is that it works with any data type.
1510543923 is stored as: 01011010 00001001 00010010 00110011
This is known as "big endian", or "MSB first", because the most significant byte (MSB, here 01011010) comes first.
I recommend against this order. If you can, swap all the bytes and store the value LSB first, i.e. with the least significant byte first, and the most significant byte last. This will make your life easier since it's the order used internally in the Arduino. If you can go little endian, then you will be able to read the data straight into the required variable, with no conversion needed, as in:
i2c_eeprom_read_buffer(0x50, 25, (byte *) &j, sizeof j);
and it will work identically with any data type.
If you cannot choose the byte order (maybe you cannot control what is inside the EEPROM), then you will have to reverse all the bytes. You can do this either with bit shifts or by explicitly moving bytes.
bytes[1] << 16
This will not work. Per the rules of the C++ language, bytes[1]
is
implicitly promoted to int
type before the shift, then it is shifted
as an int
. But on your Arduino an int
is 16-bits long, thus by
shifting it 16 positions you are dropping off all of the bits.
Actually, this is even worse: you are invoking what is known as
undefined behavior, meaning that it is considered nonsense and the
compiler is free to interpret however it wants.
To do this properly, you first have to explicitly cast bytes[i]
to
unsigned long
. It has to be unsigned because changing the sign bit on
a long
by bit shifting is also undefined behavior. Thus, the proper
way of reconstructing the number via bit shifts is:
long j = ((unsigned long) bytes[3] << 0)
| ((unsigned long) bytes[2] << 8)
| ((unsigned long) bytes[1] << 16)
| ((unsigned long) bytes[0] << 24);
This is portable (it should also work on big-endian architectures) but only works with integral types, not with floats.
My preferred option would be to use aunion
in order to access the
bytes of the variable explicitly. Then you just have to write those
bytes reversed relative to the buffer:
union { float f; byte b[4]; } data;
data.b[0] = bytes[3];
data.b[1] = bytes[2];
data.b[2] = bytes[1];
data.b[3] = bytes[0];
float x = data.f;
1510543923 is stored as: 01011010 00001001 00010010 00110011
This is known as "big endian", or "MSB first", because the most significant byte (MSB, here 01011010) comes first.
I recommend against this order. If you can, swap all the bytes and store the value LSB first, i.e. with the least significant byte first, and the most significant byte last. This will make your life easier since it's the order used internally in the Arduino. If you can go little endian, then you will be able to read the data straight into the required variable, with no conversion needed, as in:
i2c_eeprom_read_buffer(0x50, 25, (byte *) &j, sizeof j);
and it will work identically with any data type.
If you cannot choose the byte order (maybe you cannot control what is inside the EEPROM), then you will have to reverse all the bytes. You can do this either with bit shifts or by explicitly moving bytes.
bytes[1] << 16
This will not work. Per the rules of the C++ language, bytes[1]
is
implicitly promoted to int
type before the shift, then it is shifted
as an int
. But on your Arduino an int
is 16-bits long, thus by
shifting it 16 positions you are dropping off all of the bits.
Actually, this is even worse: you are invoking what is known as
undefined behavior, meaning that it is considered nonsense and the
compiler is free to interpret however it wants.
To do this properly, you first have to explicitly cast bytes[i]
to
unsigned long
. It has to be unsigned because changing the sign bit on
a long
by bit shifting is also undefined behavior. Thus, the proper
way of reconstructing the number via bit shifts is:
long j = ((unsigned long) bytes[3] << 0)
| ((unsigned long) bytes[2] << 8)
| ((unsigned long) bytes[1] << 16)
| ((unsigned long) bytes[0] << 24);
This is portable (it should also work on big-endian architectures) but only works with integral types, not with floats.
For reconstructing a float, my preferred option would be to use aunion
, in order to access the bytes of the variable explicitly. Then
you just have to copy the bytes from the buffer to the union
in
reverse order:
union { float f; byte b[4]; } data;
data.b[0] = bytes[3];
data.b[1] = bytes[2];
data.b[2] = bytes[1];
data.b[3] = bytes[0];
float x = data.f;
One nice thing about this approach is that it works with any data type.
1510543923 is stored as: 01011010 00001001 00010010 00110011
This is known as "big endian", or "MSB first", because the most significant byte (MSB, here 01011010) comes first.
I recommend against this order. If you can, swap all the bytes and store the value LSB first, i.e. with the least significant byte first, and the most significant byte last. This will make your life easier since it's the order used internally in the Arduino. If you can go little endian, then you will be able to read the data straight into the required variable, with no conversion needed, as in:
i2c_eeprom_read_buffer(0x50, 25, (byte *) &j, sizeof j);
and it will work identically with any data type.
If you cannot choose the byte order (maybe you cannot control what is inside the EEPROM), then you will have to reverse all the bytes. You can do this either with bit shifts or by explicitly moving bytes.
bytes[1] << 16
This will not work. Per the rules of the C++ language, bytes[1]
is
implicitly promoted to int
type before the shift, then it is shifted
as an int
. But on your Arduino an int
is 16-bits long, thus by
shifting it 16 positions you are dropping off all of the bits.
Actually, this is even worse: you are invoking what is known as
undefined behavior, meaning that it is considered nonsense and the
compiler is free to interpret however it wants.
To do this properly, you first have to explicitly cast bytes[i]
to
unsigned long
. It has to be unsigned because changing the sign bit on
a long
by bit shifting is also undefined behavior. Thus, the proper
way of reconstructing the number via bit shifts is:
long j = ((unsigned long) bytes[3] << 0)
| ((unsigned long) bytes[2] << 8)
| ((unsigned long) bytes[1] << 16)
| ((unsigned long) bytes[0] << 24);
This is portable (it should also work on big-endian architectures) but only works with integral types, not with floats.
My preferred option would be to use a union
in order to access the
bytes of the variable explicitly. Then you just have to write those
bytes reversed relative to the buffer:
union { float f; byte b[4]; } data;
data.b[0] = bytes[3];
data.b[1] = bytes[2];
data.b[2] = bytes[1];
data.b[3] = bytes[0];
float x = data.f;