C++:处理字节数据

3

我的问题是,我需要加载二进制文件并处理文件中的单个位。之后当然需要将其保存为字节。

我的主要问题是 - 选择什么数据类型来使用 - char还是long int?我能以某种方式使用char吗?


2
顺便问一下,你的文件有多长?已经考虑过优化问题了吗?你需要更改单个字节还是“单位比特”块的字节? - Michel Keijzers
5
使用整数来解析二进制数据很容易引起字节序问题。 - KillianDS
@Deepak:既然是一样的,为什么这里 sizefo(long int)!= sizeof(int)? - PlasmaHH
@Deepak:我建议你阅读我回答中链接的答案。它们详细介绍了类型大小的问题。 - daramarak
@Peter,我错了,它们是不同的。 - Deepak
显示剩余3条评论
6个回答

6

除非性能对于这里至关重要,否则请使用最容易理解和维护代码的方式。


1
忽略我的回答,这是规则#1。 - daramarak
2
+1 如果可能的话不要重复造轮子,如果你不必使用预定义的序列化格式,就不要去发明一个。 - KillianDS
同意,尽管重新发明轮子很有趣。"看,我的是方的" - daramarak
可能一个明确的问题会引来更详细的建议。据我所知,这并不需要过分思考手头的信息。 - Steve Townsend

5

在开始编写任何代码之前,请确保您理解endianessc++类型大小以及它们可能会有多么strange

unsigned char是唯一的固定大小类型(机器的自然字节,通常为8位)。因此,如果您设计可移植性,那是一个安全的选择。但是,使用unsigned int甚至long long来加快处理速度并使用size_of来查找每个读取中获取的位数也不难,尽管这样代码会变得更加复杂。

你应该知道,为了实现真正的可移植性,C++ 的内部类型没有一个是固定的。无符号字符可能有9位,int 可能只有0到65535的范围,如thisthis的答案所述。
另一个选择是使用boost integer library来减少所有这些不确定性,正如user1200129所建议的那样。如果你的平台上有boost的话。虽然如果选择外部库,有许多序列化库可供选择。
但首先,甚至在开始优化之前,要做一些简单的东西,让它工作。然后当你开始遇到时间问题时,你可以开始分析。

1
是的,一旦开始探索陌生的平台,编程世界就变得奇怪了;) - daramarak
你可以使用boost integer.hpp来获取可移植的整数类型。例如,如果你需要确保获得64位有符号整数,你可以在不同的编译器和操作系统中使用boost::int64_t,你将始终获得所期望的类型。当你需要reinterpret_cast数据时,这一点尤为重要。 - 01100110

3

这取决于您想要做什么,但一般来说,最好的速度是使用与程序编译相同大小的整数。因此,如果您有一个32位程序,则选择32位整数,如果您有64位,则选择64位。

如果文件中有某些字节或整数,则可能会有所不同。如果不知道文件的确切结构,则很难确定最佳值。


1

如果你正在处理字节,那么最好的方法是使用特定大小的类型。

#include <algorithm>
#include <iterator>
#include <cinttypes>
#include <vector>
#include <fstream>

int main()
{
     std::vector<int8_t> file_data;
     std::ifstream file("file_name", std::ios::binary);

     //read
     std::copy(std::istream_iterator<int8_t>(file),
               std::istream_iterator<int8_t>(),
               std::back_inserter(file_data));

     //write
     std::ofstream out("outfile");           
     std::copy(file_data.begin(), file_data.end(),
               std::ostream_iterator<int8_t>(out));

}

编辑修复了错误


uint8_t 并不保证在所有系统中都被定义。但它更清晰地表明了使用的意图。 - daramarak
C99标准已经存在很长时间了,几乎所有系统都有<stdint.h>。(老实说,我想不出一个没有的系统。这是最容易提供的头文件之一。)C++的等效物可能不存在,但这很容易解决。 - Mike DeSimone

1

你的句子并不是真正的正确英语,但就我理解问题而言,你最好使用无符号字符(即字节)类型,以便能够单独修改每个字节。

编辑:根据评论进行了更改。


2
什么是无符号字节?字节是无符号字符。 - MByD
1
现在它是比较正式的英语。 :) - Prof. Falken
由于C语言中没有byte的定义,所以无法确定它是有符号的还是无符号的。 - Mr Lister
1
@Michel,你编辑反了。你应该寻找“unsigned char”。 - Mr Lister
固定的(周五下午综合症) - Michel Keijzers
有一些平台(例如一些TI DSPs)具有16位的char,因为它们不能寻址字节。在这些平台上,sizeof(char) == 1sizeof(short) == 1sizeof(int) == 2 ... - Mike DeSimone

1
如果您需要强制规定整数类型中有多少位,您需要使用<stdint.h>头文件。它在C和C++中都存在。它定义了诸如uint8_t(8位无符号整数)之类的类型,这些类型保证在平台上解析为正确的类型。它还告诉其他程序员阅读您的代码时位数很重要。

如果你担心性能问题,你可能想使用大于8位的类型,例如uint32_t。然而,在读写文件时,你需要注意你系统的字节序。特别是,如果你有一个小端系统(例如x86,大多数ARM),那么32位值0x12345678将被写入文件作为四个字节0x78 0x56 0x34 0x12,而如果你有一个大端系统(例如Sparc,PowerPC,Cell,一些ARM和互联网),它将被写入为0x12 0x34 0x56 0x78。(读取也是如此)。当然,你可以使用8位类型来避免这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接