将一个浮点数转换为4个uint8_t

13

我有一个需要通过CAN协议发送的float变量,为了这样做,这个32位的浮点数必须被分成4个uint8_t变量。

我完全不知道该怎么做。我最初想将浮点数转换为整数,但是我在互联网上找到的一些答案,使用强制类型转换联合体似乎都无法使用。

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

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
...

2
你不想要 uint8_t[4] 而不是 4 个 uint8_t 变量吗? - trojanfoe
同时展示您正在使用的代码以及调用方法的一些思路(即其语义)。 - trojanfoe
如果可能的话,我需要4个不同的独立变量,但一个制表符也可以。我没有好的代码可以展示给你...只有使用cast和union进行测试。 - Evans Belloeil
1
重复的问题:https://dev59.com/DmEi5IYBdhLWcg3wueV0 https://dev59.com/ynXYa4cB1Zd3GeqP98Fe https://dev59.com/G2865IYBdhLWcg3wFqnY https://dev59.com/zFrUa4cB1Zd3GeqPkoji?rq=1 ... - phuclv
4个回答

8
您通常可以通过将浮点数强制转换为uint8_t数组来实现此操作。
在C语言中,您可以这样做:
uint8_t *array;
array = (uint8_t*)(&f);

在C++中最好使用reinterpret_cast

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

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

3
字节序怎么样? - Jarod42
1
可能存在字节序问题,但是无论如何我们将浮点数拆分成字节都是正确的。我认为这是一个单独的问题。无论协议规定什么,操作员都需要遵守。 - dohashi
2
我认为这个答案不应该被接受。在C++中,将类型转换为不相关的类型是未定义行为,并且可能违反严格别名规则。应该使用下面答案中建议的联合体。在C++20中,您还可以使用std::bit_cast而不是memcpy方法。 - S. Kaczor

2

首先需要注意的是标准对 float 没有特定的大小限制。在某些可想象的架构上,float 可能不适合四个字节的大小(尽管我不知道有哪些)。在尝试任何操作之前,至少应该(静态)断言它会适合。

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

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

这完全忽略了大小端问题,也许你真正想要的是复制字节,这样你就可以修复它:
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

您可以执行此非法操作:

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

虽然这通常可以正常工作,但它不受C++标准支持,编译器可能会生成具有未定义行为的代码。
另一种解决方案是使用联合体:
union{
    float f;
    uint8_t i[4];
}
f = someFloatValue;
// now i's contain the bit pattern of f

目前不确定所有编译器是否都能产生一致的结果,但这似乎比第一种方法更安全。

您也可以将f的值打包在32位整数中。然而,这可能会导致失去一些精度,但根据您希望保持f的准确程度,这可能是最好的解决方案。


我在你之前发布了一个联合答案,但后来意识到这是未定义的行为:https://dev59.com/mnPYa4cB1Zd3GeqPlqvz - eerorika
1
从不同的联合字段读取而不是最后写入的行为在技术上是未定义的。然而,所有主要的C++编译器都提供了特殊的保证,这将正确地工作。这仍然是正确的答案,因为实际上没有符合标准的其他方法来实现这一点。 - ComicSansMS
@ComicSansMS 啊,感谢您恢复我对“联合体”信心。 - eerorika

0
这里是一个基于论文的表格实现。
它将一个32位浮点数转换为一个16位浮点数,并将其存储在一个无符号16位值中。这两个LUT位于静态存储器中,因此可以创建这些数组,并且它处理所有边角情况以及速度快。(有关详细信息,请参见论文)
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
};

};


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接