13

I have got a float variable that I need to send through a CAN protocol. To do so, this float of 32 bits must be cut in 4 uint8_t variables.

I have absolutely no idea of how to do. I was first thinking of convert the float to an int but some answers that I found on the internet, which use cast or union doesn't seems to work.

Here's a simple example of what I am trying to do :

float f;
uint8_t ut1,ut2,ut3,ut4;

//8 first bits of f into ut1
//8 second bits of f in ut2
...

// Then I can send the uint8_t through CAN
...
JeJo
  • 30,635
  • 6
  • 49
  • 88
Evans Belloeil
  • 2,413
  • 7
  • 43
  • 76
  • 2
    Don't you want `uint8_t[4]` rather than 4 * `uint8_t` variables? – trojanfoe Aug 19 '14 at 14:50
  • Also show the code you using and some idea of the method you are calling (i.e. its semantics). – trojanfoe Aug 19 '14 at 14:51
  • I need 4 different separate variable if possible , but a tab can be ok. I don't have good code to show you ... only test with cast and union – Evans Belloeil Aug 19 '14 at 14:53
  • 1
    duplicate of http://stackoverflow.com/questions/21005845/how-to-get-float-bytes http://stackoverflow.com/questions/18270974/how-to-convert-a-float-to-a-4-byte-char-in-c http://stackoverflow.com/questions/3991478/building-a-32bit-float-out-of-its-4-composite-bytes-c http://stackoverflow.com/questions/7157301/convert-float-to-unsigned-long-to-access-float-internals-in-c-define?rq=1 ... – phuclv Aug 19 '14 at 16:35

4 Answers4

8

You normally do this by casting the floatto an array ofuint8_t`.

In C you can do it like this:

uint8_t *array;
array = (uint8_t*)(&f);

In C++ it's better to use reinterpret_cast:

uint8_t *array;
array = reinterpret_cast<uint8_t*>(&f);

Then array[0], ..., array[3] are your bytes.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
dohashi
  • 1,771
  • 8
  • 12
  • 3
    How about endianess ? – Jarod42 Aug 19 '14 at 14:57
  • 1
    There may be endianess issues, but that is true however we split the float into bytes. I'd say that is a separate issue. Whatever the protocol specifies the OP will need to adhere to. – dohashi Aug 19 '14 at 15:04
  • 2
    I don't think this answer should be accepted. Cast to unrelated type is an UB in c++, and it may also violate strict aliasing rule. Union should be used as suggested in answers below. In c++20 you can also use std::bit_cast instead of memcpy approach. – S. Kaczor Dec 16 '20 at 14:00
2

First you should note that the standard imposes no specific size restrictions on float. It's possible that a float wouldn't fit into four bytes on some imaginable architecture (although I'm not aware of any). You should at least (static_)assert that it will fit before attempting anything.

Then I think the simplest way is to assert that CHAR_BIT is 8, and use the legal aliasing to unsigned char* with reinterpret_cast:

static_assert(sizeof(float) == 4);
float f = 0; // whatever value
unsigned char* float_as_char = reinterpret_cast<unsigned char*>(&f);

This totally ignores the endian issue though, so maybe what you really want is to make a copy of the bytes so you can fix that up:

static_assert(sizeof(float) == 4);
float f = 0; // whatever value
uint8_t bytes[4];
std::memcpy(bytes, &f);
// Fix up the order of the bytes in "bytes" now.
Mark B
  • 95,107
  • 10
  • 109
  • 188
1

You can do this illegal operation:

float f = someFloatValue;
uint8_t* i = reinterpret_cast<uint8_t*>(&f);

Although this works most of the time, it is not supported by c++ standard and compilers might generate code with undefined behaviour.

Another solution is using unions:

union{
    float f;
    uint8_t i[4];
}
f = someFloatValue;
// now i's contain the bit pattern of f

It's unclear if all compilers yield consistent results, but it seems safer than the first aproach.

You can also pack the value of f in a 32-bit integer. This, however can result in losing a bit of precision, but depending on how accurately you want to keep f, would be the best solution.

rashmatash
  • 1,699
  • 13
  • 23
  • I posted a union answer just before you, but then I realized that it's undefined behaviour: http://stackoverflow.com/questions/17273320/c-undefined-behaviour-with-unions – eerorika Aug 19 '14 at 15:04
  • 1
    Technically, reading from a different union field than the last written to is undefined behavior. However, all major C++ compilers give special guarantees that this will work correctly. This is still the correct answer as there actually is no standard conforming way to achieve this otherwise. – ComicSansMS Aug 19 '14 at 15:06
  • @ComicSansMS Ah, thanks for restoring my faith in the `union`. – eerorika Aug 19 '14 at 15:08
0

Here is a table based implementation based off this paper

It converts a 32 bit floating point number to a 16 bit floating point number which it stores in an unsigned 16 bit value. The two LUT's are in static memory so arrays of these can be created, and it handles all the corner cases along with being fast.(see the paper for details)

using flt32 = float;
class flt16 {
public: // clucnky but functional and fast
flt16(flt32 in) { 
    ftoi_t fi{ in };
    half = basetable[(fi.i >> 23) & 0x1ff] + ((fi.i & 0x007fffff) >> shifttable[(fi.i >> 23) & 0x1ff]);
}

union ftoi_t{
    flt32 f;
    uint32 i;
};

uint16 half;

static constexpr uint16 basetable[512] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
    9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 17408, 18432, 19456, 20480, 21504, 22528,
    23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
    31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
    32769, 32770, 32772, 32776, 32784, 32800, 32832, 32896, 33024, 33280, 33792, 34816, 35840, 36864,
    37888, 38912, 39936, 40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128, 49152, 50176, 51200,
    52224, 53248, 54272, 55296, 56320, 57344, 58368, 59392, 60416, 61440, 62464, 63488, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
    64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512
};

static constexpr uint8 shifttable[512] = {
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 
    14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 
    13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 
    18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 
    13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 
    24, 24, 24, 24, 24, 24, 24, 13
};

};

pmw1234
  • 206
  • 1
  • 7