Skip to main content
Arduino

Return to Answer

union works with any data type.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

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.

Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

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;
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /