【问题标题】:How can I add a 64 bit floating point number to an unsigned char array at specific indexes (C++)如何将 64 位浮点数添加到特定索引处的无符号字符数组(C++)
【发布时间】:2021-02-22 18:20:35
【问题描述】:

我需要将一个 64 位浮点数添加到特定索引处的 unsigned char 数组中(例如,索引 18)。

例如unsigned char数组:

unsigned char msg[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

我想在索引1,2,3,4,5,6,7,8 处的无符号字符数组中添加一个浮点数,例如0.084,以十六进制(小端序)表示为1B2FDD240681B53F,并保留索引0 和@ 987654330@不变。

所以,我希望 unsigned char 数组 msg 包含以下内容:

msg = {0x00, 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x81, 0xB5, 0x3F, 0x00}

到目前为止,我可以使用以下代码获得具有示例浮点值 0.084 的十六进制表示形式的 std::string,但我不确定如何将字符串值添加回 unsigned char 数组:

#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++ 解决方案。

【问题讨论】:

  • @Adrian Mole:除了 Adrian Mole 的解决方案之外,您为什么还要考虑考虑其他问题?
  • @paulsm4 为什么 OP 甚至会考虑考虑将序列化为字节数组,除非他们正在执行文件存储或网络通信。在这些情况下,Adrian Mole 的解决方案存在不同字节序的系统之间不兼容的问题。不过,限制在一个系统内也没问题。
  • 这是用于网络通信的 - 我原本以为我必须颠倒顺序,我在使用字符串之前已经这样做了,但我相信两个系统都是小端的,所以 memcpy 解决方案似乎工作正常.
  • @user3716193 the memcpy solution seems to work fine 如果您只在一个或相同字节序的系统上进行测试,可能看起来如此。它在不同字节序的系统之间不起作用,这通常是网络通信中应该考虑的一种可能性。
  • 对于一个独立的应用程序,担心“字节顺序”......是愚蠢的。然而,对于网络消息,它可能是ESSENTIAL。坦率地说,我没有注意到变量名是“msg”; OP也没有在他的帖子中明确表示。 “网络消息”肯定需要“更强大”的解决方案……

标签: c++ arrays c char stdstring


【解决方案1】:

由于从联合的非活动成员读取,您的示例具有未定义的行为。一种明确定义的转换为整数的方法:

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::bit_cast 对我不可用,我使用的是 C++ 11。
  • @user3716193 您可以使用std::memcpy 编写自己的not_std::bit_cast 并改用它。
  • 最终使用 std::memcpy。虽然赞成这个答案 - 我认为这是我最初想要进入的方向 - 能够使用按位运算,因为我之前已经将它们与整数一起使用,我只是无法弄清楚如何使用浮点数来做到这一点。谢谢。
【解决方案2】:

将组件字节格式化为十六进制字符串,然后再次读回这些字节是非常浪费时间和精力的。只需使用 std::memcpy()(在 C++ 中)或 memcpy(在 C 中):

    std::memcpy(&msg[1], &dVal, sizeof(dVal));

这将解决所有必需的指针对齐问题。但是,它不会对您的字节顺序进行任何“解释” - 但这应该不是问题,除非您随后在不同平台之间传输该字节数组。

【讨论】:

  • 出于某种原因,我一直认为我需要单独添加每个字节以将它们放在数组中的正确索引处,这是我的错误。我绝对认为我的字符串方法效率很低。这很好用,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2011-04-23
  • 1970-01-01
  • 2012-01-20
  • 1970-01-01
相关资源
最近更新 更多