【问题标题】:read float and double from binary data in C++从 C++ 中的二进制数据中读取浮点数和双精度数
【发布时间】:2012-12-02 14:39:05
【问题描述】:

我需要能够从 C++ 中的二进制数据中读取浮点数或双精度数,类似于 Python 的 struct.unpack 函数。我的问题是我收到的数据总是大端的。我已经处理了整数值as described here 的问题,但是逐字节工作不适用于浮点值。我需要一种在 C++ 中提取浮点值(32 位 floats 和 64 位 doubles)的方法,类似于在 Python 中使用 struct.unpack(">f", num)struct.unpack(">d", num) 的方式。

这是我尝试过的一个示例:

stuct.unpack("d", num) ==> *(double*) str; // if str is a char* containing the data

如果str 是 little-endian 则效果很好,但如果它是 big-endian 则不行,因为我知道它将永远如此。问题是我不知道环境的原生字节序是什么,所以我需要能够随时将二进制数据提取为大字节序。

如果您查看链接的问题,您会发现这很容易对整数值使用按位或位移,但该方法不适用于浮点。

注意我应该早点指出这一点,但我不能使用 c++11 或 Boost 以外的任何第三方库。

【问题讨论】:

  • stackoverflow.com/questions/5242589/… 这个问题已经被覆盖了
  • 你尝试过什么?有什么区别?演员表?
  • 我可能会建议使用某种消息打包库(MessagePack、Protobufs、Thrift 等)而不是尝试手动执行此操作...这几乎会让你秃头和这些库使这类事情变得非常琐碎......
  • @kassak 这如何回答我的问题?问题不是“它会受到影响吗?”。显然是这样,因为我遇到了这个问题。问题是“我该如何解决?”
  • 如果字节序不同,那么您是在两种不同类型的机器之间交谈。浮点格式具有更多变量,而不仅仅是机器类型之间的字节序。

标签: c++ python floating-point binary endianness


【解决方案1】:

为什么逐字节工作不适用于浮点值? 只需像往常一样提取 32 位整数,然后将其重新解释为浮点数:float f = *(float*)&i

对于 64 位整数和双精度数也是如此

【讨论】:

  • 这适用于 32 位(位移为long,转换为float),但在 64 位上失败(long long -> double)。
  • 我还想快速指出,在 C++ 中你真的应该使用 reinterpret_cast/static_cast/dynamic_cast/const_cast 而不是 C 风格的强制转换。但在这里不应该有所作为
  • C 标准不保证通过指针转换重新解释对象有效,因此未定义将int * 转换为float * 并取消引用它。存储到联合成员中并从另一个联合成员中读取被定义为将字节重新解释为新类型。您可以使用float f = (union { unsigned int i; float f; }) {i}.f; 执行此操作,前提是floatunsigned int 适用于目标平台(每个四个字节,等等)。
【解决方案2】:
void ByteSwap(void * data, int size)
{
    char * ptr = (char *) data;
    for (int i = 0;  i < size/2;  ++i)
        std::swap(ptr[i], ptr[size-1-i]);
}

bool LittleEndian()
{
    int test = 1;
    return *((char *)&test) == 1;
}

if (LittleEndian())
    ByteSwap(&my_double, sizeof(double));

【讨论】:

  • 这成功地从 one-endian 切换到 other-endian,但并没有解决根本问题,我的数据将始终是 big-endian,但我不知道机器是否会是。
  • @ewok,好的,我已经为你添加了一点。
  • @EricPostpischil,我还记得char* 的一个例外,尽管那是我在 StackOverflow 上听到的传闻。但是当你想一想,fread 这样的东西还能如何工作?
  • 哦,当然,char 很特别。没关系。该评论属于另一个答案,它将int * 转换为float *。顺便说一句,fread 不是反例。声明采用void *。此外,允许编译器对其进行特殊处理,因为它是在标准中定义的。
猜你喜欢
  • 2011-05-09
  • 2016-02-15
  • 2015-04-30
  • 2014-02-07
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 2013-08-30
相关资源
最近更新 更多