如何将 64 位浮点数添加到特定索引处的无符号字符数组 (C++)
How can I add a 64 bit floating point number to an unsigned char array at specific indexes (C++)
我需要将 64 位浮点数添加到特定索引处的 unsigned char
数组中(例如索引 1
到 8
)。
示例 unsigned char
数组:
unsigned char msg[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
我想添加一个浮点数,例如 0.084
,它在索引 1,2,3,4,5,6,7,8
处的无符号字符数组中以十六进制(小端)表示为 1B2FDD240681B53F
并保持索引 0
和 9
不变。
所以,我希望无符号字符数组 msg
包含以下内容:
msg = {0x00, 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x81, 0xB5, 0x3F, 0x00}
到目前为止,我可以使用以下代码获得 std::string
示例浮点值 0.084
的十六进制表示,但我不确定如何将字符串值添加回无符号字符数组:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main()
{
union udoub
{
double d;
unsigned long long u;
};
double dVal = 0.084;
udoub val;
val.d = dVal;
std::stringstream ss;
ss << std::setw(16) << std::setfill('0') << std::hex << val.u << std::endl;
std::string strValHexString = ss.str();
cout<< strValHexString << std::endl;
return 0;
}
输出:
3fb5810624dd2f1b
我尝试使用 std::copy
像下面的例子一样将值从 std::string
复制到 unsigned char
但它似乎没有做我想要的:
unsigned char ucTmp[2];
std::copy(strValHexString.substr(0,2).begin(), strValHexString.substr(0,2).end(), ucTmp);
正在寻找 C 或 C++ 解决方案。
由于从联合的非活动成员读取,您的示例具有未定义的行为。一种明确定义的转换为整数的方法:
auto uVal = std::bit_cast<std::uint64_t>(dVal);
现在您已经有了整数形式的数据,您可以使用按位运算来提取特定位置的各个八位字节:
msg[1] = (uVal >> 0x0 ) & 0xff;
msg[2] = (uVal >> 0x8 ) & 0xff;
msg[3] = (uVal >> 0x10) & 0xff;
msg[4] = (uVal >> 0x18) & 0xff;
msg[5] = (uVal >> 0x20) & 0xff;
...
这可以压缩成一个循环。
请注意,无论 CPU 的字节顺序如何,这都以相同的方式工作。与直接 std::memcpy
方法不同的是,数组中的结果顺序将始终是小端序,后者会导致本机字节序,这在所有系统上都不一定是小端序。但是,如果浮点数和整数使用不同的字节顺序,那么即使使用这种方法,顺序也不会相同。
将组件字节格式化为十六进制字符串,然后再次读回这些字节是一种可怕的时间和精力浪费。只需使用 std::memcpy()
(在 C++ 中)或 memcpy
(在 C 中):
std::memcpy(&msg[1], &dVal, sizeof(dVal));
这将解决所有必需的指针对齐问题。但是,就字节顺序而言,它不会做任何 'interpretation' - 但这应该不是问题,除非您随后在不同平台之间传输该字节数组。
我需要将 64 位浮点数添加到特定索引处的 unsigned char
数组中(例如索引 1
到 8
)。
示例 unsigned char
数组:
unsigned char msg[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
我想添加一个浮点数,例如 0.084
,它在索引 1,2,3,4,5,6,7,8
处的无符号字符数组中以十六进制(小端)表示为 1B2FDD240681B53F
并保持索引 0
和 9
不变。
所以,我希望无符号字符数组 msg
包含以下内容:
msg = {0x00, 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x81, 0xB5, 0x3F, 0x00}
到目前为止,我可以使用以下代码获得 std::string
示例浮点值 0.084
的十六进制表示,但我不确定如何将字符串值添加回无符号字符数组:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main()
{
union udoub
{
double d;
unsigned long long u;
};
double dVal = 0.084;
udoub val;
val.d = dVal;
std::stringstream ss;
ss << std::setw(16) << std::setfill('0') << std::hex << val.u << std::endl;
std::string strValHexString = ss.str();
cout<< strValHexString << std::endl;
return 0;
}
输出:
3fb5810624dd2f1b
我尝试使用 std::copy
像下面的例子一样将值从 std::string
复制到 unsigned char
但它似乎没有做我想要的:
unsigned char ucTmp[2];
std::copy(strValHexString.substr(0,2).begin(), strValHexString.substr(0,2).end(), ucTmp);
正在寻找 C 或 C++ 解决方案。
由于从联合的非活动成员读取,您的示例具有未定义的行为。一种明确定义的转换为整数的方法:
auto uVal = std::bit_cast<std::uint64_t>(dVal);
现在您已经有了整数形式的数据,您可以使用按位运算来提取特定位置的各个八位字节:
msg[1] = (uVal >> 0x0 ) & 0xff;
msg[2] = (uVal >> 0x8 ) & 0xff;
msg[3] = (uVal >> 0x10) & 0xff;
msg[4] = (uVal >> 0x18) & 0xff;
msg[5] = (uVal >> 0x20) & 0xff;
...
这可以压缩成一个循环。
请注意,无论 CPU 的字节顺序如何,这都以相同的方式工作。与直接 std::memcpy
方法不同的是,数组中的结果顺序将始终是小端序,后者会导致本机字节序,这在所有系统上都不一定是小端序。但是,如果浮点数和整数使用不同的字节顺序,那么即使使用这种方法,顺序也不会相同。
将组件字节格式化为十六进制字符串,然后再次读回这些字节是一种可怕的时间和精力浪费。只需使用 std::memcpy()
(在 C++ 中)或 memcpy
(在 C 中):
std::memcpy(&msg[1], &dVal, sizeof(dVal));
这将解决所有必需的指针对齐问题。但是,就字节顺序而言,它不会做任何 'interpretation' - 但这应该不是问题,除非您随后在不同平台之间传输该字节数组。