8

我的代码使用带有二进制标志集的 fstream 并使用未格式化的 I/O 函数读取和写入来操作二进制文件。这在我曾经使用过的所有系统上都能正常工作(文件中的位与预期完全相同),但这些基本上都是美国英语。我一直想知道这些字节是否有可能被不同系统上的编解码器修改。

听起来标准说使用未格式化的 I/O 与使用 sputc/sgetc 将字符放入流缓冲区中的行为相同。这些将导致streambuf 中的溢出或下溢函数被调用,听起来这些会导致某些东西通过一些codecvt(例如,参见c++ 标准中的27.8.1.4.3)。对于 basic_filebuf,此编解码器的创建在 27.8.1.1.5 中指定。这使得结果看起来取决于 basic_filebuf.getloc() 返回的内容。

所以,我的问题是,我是否可以假设在一个系统上使用 ofstream.write 写出的字符数组可以在另一个系统上使用 ifstream.read 逐字恢复,无论任何人可能在他们的系统上使用什么语言环境配置?我会做出以下假设:

  1. 该程序正在使用默认区域设置(即,该程序根本没有更改区域设置本身)。
  2. 系统都具有 CHAR_BIT 8,每个字节内具有相同的位顺序,将文件存储为八位字节等。
  3. 流对象设置了二进制标志。
  4. 在这个阶段,我们不需要担心任何字节序差异。如果将数组中的任何字节解释为多字节值,则将在稍后阶段根据需要处理字节顺序转换。

如果默认语言环境不能保证在某些系统配置(我不知道,阿拉伯语或其他东西)上未经修改地通过这些东西,那么使用 C++ 编写二进制文件的最佳方法是什么?

4

3 回答 3

1

如果您设置了二进制标志,则您编写的所有内容都将逐字写入文件。没有转换。如何解释字节取决于您(可能还有语言环境)。

还有一件事:在不同的语言环境中存在破损的可能性。例如,如果您的数据源基于区域设置创建了二进制数据(并且此数据的格式会根据区域设置而变化 - 这是一个坏主意)。当在具有不同语言环境的机器上加载数据时,这会导致麻烦。这是一个设计错误。

如果您只使用具有相同格式/布局的标准数据类型/结构,无论它们是在什么语言环境中创建的,都应该没问题。

于 2009-12-03T00:04:39.600 回答
1

谢谢您的帮助。我只是认为发布一些不适合评论的其他信息可能会有所帮助。

C++ 程序的默认语言环境始终是“C”语言环境 ( http://www.cplusplus.com/reference/clibrary/clocale/setlocale/ )。如果这是您的程序中使用的唯一语言环境,则意味着该行为不依赖于运行它的机器的特定语言环境配置。这也意味着 char 的未格式化 I/O 不会进行任何代码转换(不过 wchar_t 可能是另一回事)。这意味着(鉴于问题中的假设)读取和写入应该允许在未修改的情况下恢复二进制数据。

(通过阅读文档)您可以通过调用 setlocale(LC_ALL,"") 全局设置应用程序的区域设置以匹配系统默认设置,这意味着从该点构造的流将使用系统默认区域设置。要将其设置回“C”语言环境,您可以调用 setlocale(LC_ALL, "C"),这意味着这将是未来构建的流将使用的。您还可以指定“C”本地应该用于已通过调用 stream.imbue(locale::classic()) 构造的流。

于 2009-12-04T02:50:27.930 回答
0

在 Windows 上应该没问题,但在其他操作系统上,您还应该检查行尾(为了安全起见)。默认的 C/C++ 语言环境是“C”,它依赖于系统的语言环境。

这不是保证。如您所知,C/C++ 编译器及其目标机器差异很大。因此,如果您保留所有这些假设,那么您就是在等待麻烦的到来。除非您尝试使其每秒数百次,否则更改语言环境的开销可以忽略不计。

于 2009-12-02T08:40:46.350 回答