【问题标题】:How to read big endian integers from file in C++? [duplicate]如何在 C++ 中从文件中读取大端整数? [复制]
【发布时间】:2013-11-03 17:28:33
【问题描述】:

假设我有一个二进制文件;它包含正二进制数,但用大端写成 32 位整数

如何阅读此文件?我现在有这个。

int main() {
    FILE * fp;
    char buffer[4];
    int num = 0;
    fp=fopen("file.bin","rb");
    while ( fread(&buffer, 1, 4,fp) != 0) {

        // I think buffer should be 32 bit integer I read,
        // how can I let num equal to 32 bit big endian integer?
    }
    return 0;
}

【问题讨论】:

  • 只是好奇 - 为什么你的代码与这个相同:stackoverflow.com/questions/13001183/…? ;-)
  • 避免使用 fopen 并使用适当的 RAII 感知类,例如 std::fstream。你的代码可能是异常不安全的,而且你没有调用fclose,所以你正在泄漏资源。

标签: c++


【解决方案1】:

将缓冲区声明为:

unsigned char buffer[4];

你可以用它来转换字节序:

int num = (int)buffer[0] | (int)buffer[1]<<8 | (int)buffer[2]<<16 | (int)buffer[3]<<24;

顺便说一句

当然,这适用于小端序的 x86 架构 - 否则您的平台字节序可能与文件的字节序匹配,因此无需转换。这样你就可以直接读入你的 int 而无需转换。

【讨论】:

  • 这个答案是针对小端的。对于大端,使用这个。 int num = (int)buffer[3] | (int)buffer[2]&lt;&lt;8 | (int)buffer[1]&lt;&lt;16 | (int)buffer[0]&lt;&lt;24;
【解决方案2】:

你需要先找出你的字节序:

How can I find Endian-ness of my PC programmatically using C?

那么你需要采取相应的行动。如果您与文件相同,则可以按原样读取值,如果您处于不同的字节序,则需要重新排序字节:

union Num 
{
    char buffer[4];
    int num;
} num ;

void swapChars(char* pChar1, char* pChar2)
{
    char temp = *pChar1;
    *pChar1 = *pChar2;
    *pChar2 = temp;
}

int swapOrder(Num num)
{
    swapChar( &num.buffer[0], &num.buffer[3]);
    swapChar( &num.buffer[1], &num.buffer[2]);

    return num.num; 
}

while ( fread(&num.buffer, 1, 4,fp) != 0)
{
    int convertedNum;
    if (1 == amIBigEndian) 
    {
        convertedNum = num.num
    } 
    else
    {
        convertedNum = swapOrder(num);
    }
    // Do what ever you want with convertedNum here...
}

【讨论】:

  • 这太慢了。交换一个表达式,不要在每个循环调用中检查字节顺序。在大多数情况下,甚至在程序启动之前就知道字节序。
  • @Artur 我必须同意!如果我们知道它是一种大端格式,为什么不简单地使用ntohl()。这通常实现为针对 MCU 优化的小型 asm {} sn-p。
  • 对于我正在编写的实际解决方案,我可能会使用操作系统提供的东西或我正在使用的库(例如 ACE_SWAP())。对于一个通用问题,这是一个通用答案。关于性能,如果没有基准测试,我不会放弃解决方案。
【解决方案3】:

它是特定于操作系统和处理器架构的。

您可能会使用htonl(3)ntohl 等例程...

但您确实应该以明确的格式使用serialized

在当前机器上(I/O 非常慢,w.r.t. CPU 速度)我赞成使用文本序列化格式,如 JSONYAML、...。但您也可以使用二进制序列化(和库),例如 BSONXDRASN.1s11n 库......

如果可能,改进生产者代码(编写您的file.bin 文件)和相应的消费者代码。

二进制数据本质上是脆弱的,因为它是特定于系统和架构的。至少,将其格式记录得非常好,最好提供一些工具来将其从文本格式转换为文本格式。

有几个用于 C++ 的 JSON 库,例如 jsoncpprapidjson 以及用于 C 的 jansson 等...

【讨论】:

  • Android 以其对 JSON 的良好支持而闻名。它也有 sqlite.
  • 但这些可能是不好的原因。如今,数据比代码重要得多!
  • ntohl 会不会更好?在网络中,我们以大端存储所有内容,因此如果要将其转换为本地,则应使用ntohl(网络到家庭)。
猜你喜欢
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多