将一个浮点数分成4个uint8_ts,然后合并在一起



我正在开发RF连接的客户端(C)和服务器端(c++)。我需要发送一个浮点值,但是架构设置的方式,我必须安排我的消息在一个结构体,限制我的3个uint8t参数:p0, p1, p2。我的解决方案是将浮点数分解为4个uint8_ts数组,并发送2个单独的消息,并使用p0作为消息是否包含前半段或后半段的标识符。

到目前为止,我有这样的东西:

服务器(c++):

sendFloat(float f)
{
messageStruct msg1, msg2;
uint8_t* array = (uint8_t*)(&f);
msg1.p0 = 1; //1 means it's the first half
msg1.p1 = array[0];
msg1.p2 = array[1];
msg2.p0 = 0; //0 means it's the second half
msg2.p1 = array[2];
msg2.p2 = array[3];
sendOverRf(msg1);
sendOverRf(msg2);
}

客户机(C):

processReceivedMessage (uint32_t id, uint32_t byteA, uint32_t byteB) //(p0,p1,p2) are routed here
{
static uint32_t firsHalfOfFloat;
uint32_t ondHalfOfFloat;
float combinedFloat;

if(id == 1) //first half
{
firstHalfOfFloat = (byteA << 8) | byteB;
}
else        //second half
{
secondHalfOfFloat = (byteA << 8) | byteB;
combinedFloat = (float)((firstHalfOfFloat << 16) | secondHalfOfFloat);
}

writeFloatToFile(combinedFloat);
}  

然后在请求时,客户端必须将该float返回

客户机(C):

sendFloatBack(uint8_t firstHalfIdentifier) // is commanded twice by server with both 0 and 1 ids
{
messageStruct msg;
float f = getFloatFromFile();
uint8_t* array = (uint8_t*)(&f);

msg.p0 = firstHalfIdentifier;
if(firstHalfIdentifier == 1) //First half
{
msg.p1 = array[0];
msg.p2 = array[1];       
}
else                         //Second half
{
msg.p1 = array[2];
msg.p2 = array[3];  
}

sendOverRf(msg);
}

,最后服务器(c++)得到返回的值:

retrieveFunc()
{
float f;
uint32_t firstHalf;
uint32_t secondHalf;

messageStruct msg = recieveOverRf();
firstHalf = (msg.p1 << 8) | msg.p2;
msg = receiveOverRf();
firstHalf = (msg.p1 << 8) | msg.p2;
f = (firstHalf << 16) | secondHalf;  
}

但是我得到了错误的值。如果有任何帮助就太好了。

union是一种非常方便的方法,可以将float反汇编为单个字节,然后再将这些字节重新组合在一起。下面是一些示例代码,说明如何做到这一点:

#include <stdio.h>
#include <stdint.h>
typedef union {
uint8_t _asBytes[4];
float   _asFloat;
} FloatBytesConverter;
int main(int argc, char** argv)
{
FloatBytesConverter fbc;
fbc._asFloat = 3.14159;
printf("Original float value is:  %fn", fbc._asFloat);
printf("The bytes of the float are:  %u, %u, %u, %un"
, fbc._asBytes[0]
, fbc._asBytes[1]
, fbc._asBytes[2]
, fbc._asBytes[3]);
// Now let's put the float back together from the individual bytes
FloatBytesConverter ac;
ac._asBytes[0] = fbc._asBytes[0];
ac._asBytes[1] = fbc._asBytes[1];
ac._asBytes[2] = fbc._asBytes[2];
ac._asBytes[3] = fbc._asBytes[3];
printf("Restored float is %fn", ac._asFloat);
return 0;
}

memcpy是你的朋友。

float toFloat(const uint8_t *arr)
{
float result;
memcpy(&result, arr, sizeof(result));
return result;
}
uint8_t *toArray(const float x, uint8_t * const arr)
{
memcpy(arr, &x, sizeof(x));
return arr;
}
void sendFloat(float f)
{
messageStruct msg1, msg2;
uint8_t array[4];
toArray(f, array);
msg1.p0 = 1; //1 means it's the first half
msg1.p1 = array[0];
msg1.p2 = array[1];
msg2.p0 = 0; //0 means it's the second half
msg2.p1 = array[2];
msg2.p2 = array[3];
sendOverRf(msg1);
sendOverRf(msg2);
}
float retrieveFunc(void)
{
float f;
unit8_t array[4]

messageStruct msg = recieveOverRf();
array[0] = msg.p1;
array[1] = msg.p2;
msg = receiveOverRf();
array[2] = msg.p1;
array[3] = msg.p2;
return toFloat(array);
}

就架构而言,字节就是字节。

我们假设两边都使用IEEE 754(或其他)。

我们可以用memcpy将一个float(4字节)放入/取出一个uint32_t

但是,我们必须处理处理器端序。

编辑:

的问题是,p0, p1, p2都是uint8_ts。- - - - - -TheBigJabronie

哎呀,我的错。我已经更新了代码,只使用字节[我在下面留下了我的原始/不正确的答案供参考]。


这是更新后的代码。这些函数将在任意一台主机上工作,而不考虑每个体系结构的端序。

注意,您的主要问题是float的编码。因此,下面的代码假设数据包完好无损地到达(即重试/重发在较低的RF层完成)

void
sendFloat(float f)
{
messageStruct msg;
uint32_t i32;
assert(sizeof(float) == sizeof(uint32_t));
// get bytes of the float in native endian order
memcpy(&i32,&f,sizeof(i32));
// handle endianness
i32 = htonl(i32);
// send MSW half
msg.p0 = 1;
msg.p1 = i32 >> 24;
msg.p2 = i32 >> 16;
sendOverRf(msg);
// send LSW half
msg.p0 = 2;
msg.p1 = i32 >> 8;
msg.p2 = i32 >> 0;
sendOverRf(msg);
}
float
recvFloat(void)
{
uint32_t i32 = 0;
float f;
messageStruct msg;
// NOTE: the two packets _should_ come in the same order as the sender, but
// we'll handle out of order packets to be complete
for (int rcount = 0;  rcount < 2;  ++rcount) {
msg = recieveOverRf();
uint32_t tmp = msg.p1;
tmp <<= 8;
tmp |= msg.p2;
switch (msg.p0) {
case 1:
i32 |= tmp << 16;
break;
case 2:
i32 |= tmp << 0;
break;
}
}
// handle endianness
i32 = ntohl(i32);
// get bytes into float
memcpy(&f,&i32,sizeof(float));
return f;
}

我的原始代码和进一步的假设

我们可以在单个消息中做到这一点,并且有足够的空间。

下面是我将使用的代码:

void
sendFloat(float f)
{
messageStruct msg;
uint32_t i32;
assert(sizeof(float) == sizeof(uint32_t));
// get bytes of the float in native endian order
memcpy(&i32,&f,sizeof(i32));
// handle endianness
i32 = htonl(i32);
// means we're sending a float
msg.p0 = CMD_FLOAT;
msg.p1 = i32;
msg.p2 = 0;
sendOverRf(msg);
}
float
recvFloat(void)
{
uint32_t i32;
float f;
messageStruct msg = recieveOverRf();
// ensure we got correct message
if (msg.p0 != CMD_FLOAT)
exit(1);
// get int in network order
i32 = msg.p1;
// handle endianness
i32 = ntohl(i32);
// get bytes into float
memcpy(&f,&i32,sizeof(float));
return f;
}

最新更新