关于C ++:将float转换为4 uint8_t

Convert a float to 4 uint8_t

我有一个需要通过CAN协议发送的float变量。 为此,必须在4个uint8_t变量中剪切此32位浮点数。

我绝对不知道该怎么做。 我最初想到的是将float转换为int,但是我在互联网上找到的使用cast或union的一些答案似乎无效。

这是我尝试做的一个简单示例:

1
2
3
4
5
6
7
8
9
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
...


通常,您可以通过将浮点数强制转换为uint8_t数组来实现此目的。

在C中,您可以这样操作:

1
2
uint8_t *array;
array = (unit8_t*)(&f);

在C ++中使用reinterpret_cast

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

然后array [0],...,array [3]是您的字节。


首先,您应该注意,该标准没有对float施加特定的大小限制。在某些可构想的体系结构上,float可能无法放入四个字节中(尽管我什么都不知道)。在尝试任何操作之前,您至少应(static_)断言它将适合。

然后,我认为最简单的方法是断言CHAR_BIT8,并对unsigned char*reinterpret_cast使用合法别名:

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

但是,这完全忽略了字节序问题,因此也许您真正想要的是复制字节,以便您可以解决此问题:

1
2
3
4
5
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.


您可以执行以下非法操作:

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

尽管这在大多数情况下都有效,但是c ++标准不支持它,并且编译器可能会生成具有未定义行为的代码。

另一个解决方案是使用联合:

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

尚不清楚是否所有编译器都能产生一致的结果,但似乎比第一个方法更安全。

您还可以将f的值打包为32位整数。但是,这可能会导致精度降低,但是根据您想要保持f的精度,这将是最佳解决方案。


这是一种联合方法,为整数部分(而不是一个数组)提供单独的名称:

1
2
3
4
5
6
7
8
union {
    float f;
    struct {
        uint8_t ut1, ut2, ut3, ut4;
    } bytes;
} value;
value.f = 1.f;
uint8_t first = value.bytes.ut1;

最初,我担心根据标准使用union并不完全合法:C ++带有联合的未定义行为,但ComicSansMS在对rashmatash答案的评论中的论点令人信服。