尝试将数字写入二进制文件时引发异常

Posted

技术标签:

【中文标题】尝试将数字写入二进制文件时引发异常【英文标题】:Exception is thrown when trying to write a number to a binary file 【发布时间】:2018-10-04 15:26:08 【问题描述】:

我一直在尝试用 C++ 创建自己的二进制文件。我正在做的是我定义了一个结构,它实际上与 dds 标头的结构相同。所以我要做的是首先向二进制文件写入一个小版本号,以查看我处于哪个阶段,然后我将整个结构写入文件,最后我将一个简单的文本字符串写入文件。 但是,当我尝试将版本号写入文件时,会引发如下异常:“TestApplication7.exe 中在 0x0F377236 (msvcp140d.dll) 处引发异常:0xC0000005:访问冲突读取位置 0x499602DB。”

所以基本上我所做的是在我的 cpp 文件顶部定义一个版本号,如下所示:

#define VERSION_NR 0x499602DB

然后我只是想把这个数字写入二进制文件。

这是我的示例代码:

 void  MyFile::Save(std::string ddsPath, MyFile::FileHeader header, const std::string texturePath) 
     header.PathLen = texturePath.length();
     const char* bufferreinterpret_cast<const char*>(&texturePath);
     const char* versionreinterpret_cast<const char*>(VERSION_NR);

     std::ofstream output(ddsPath, std::ios::binary);
     output.write(version, sizeof(VERSION_NR)); //Here is where the exception is thrown
     ext->WriteStruct(output, header); //Writing the hole header to the file
     output << texturePath; //Outputting a simple text to the file

原来是这样的代码:

output.write(version, sizeof(VERSION_NR));

这导致异常被抛出,我不知道我做错了什么,因为我对 c++ 编程非常陌生。我确实尝试在“保存”方法中创建一个 const DWORD 而不是使用宏,但我仍然遇到相同的异常。 我不知道这是否有帮助,除了“访问冲突读取位置 0x499602DB”的消息与我的宏的值相同的“位置”。

如果有人可以帮助我,或者只是指出我正确的方向,我将不胜感激。 谢谢!

【问题讨论】:

首先摆脱那些reinterpret_casts。对于初学者来说,规则是reinterpret_cast 总是错误的。 显示的代码似乎试图将reinterpret_cast 指向std::string 的指针转换为const char *。那是... 不起作用。这是对 C++ 工作原理以及 C++ 对象的全部含义的根本误解。 @PeteBecker a reinterpret_cast 或 c 样式转换在将数字写入二进制 std::ostream 时很难避免 @SamVarshavchik 是的,那行代码只是我在弄清楚这一切如何工作时所做的事情,我没有在方法中的任何地方使用它,所以它只是我忘记的一些剩菜删除。感谢您指出! @AlanBirtles -- reinterpret_cast 在这里很容易避免。 static_cast&lt;const char*&gt;(static_cast&lt;void*&gt;(&amp;whatever))。并且这种强制转换组合不会将整数值转换为指针。 【参考方案1】:

如果我们去掉宏和许多其他不相关的代码,我们会得到:

int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));

您是正确的,您的版本值出现在错误消息中这一事实是一个线索。第二行将整数值转换为地址为0x499602DB 的字符指针。由于当output.write 尝试访问该地址时,该地址未指向有效的内存地址,因此操作系统不允许该操作并引发访问冲突。

正确的代码是:

int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(&version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));

或者如果你想写一个字符串,就避免一起转换:

const char version[4] = '\xDB','\x02','\x96','\x49';
std::ofstream output("out.bin", std::ios::binary);
output.write(version, sizeof(version));

另请注意,一旦我们修复了此崩溃,以下内容也是不正确的:

const char* bufferreinterpret_cast<const char*>(&texturePath);

而且应该是:

const char* buffer = texturePath.c_str();

texturePath 是一个std::string 对象,指向它的指针不能转换为char*c_str() 方法返回一个const char* 指针,然后您可以将其传递给std::ofstream::write,或者只使用@987654334 @ 就像你已经在做的那样,只需删除 buffer 变量。

【讨论】:

【参考方案2】:

VERSION_NR 不是变量,因此 char* 指向随机内存。 不要使用宏,创建一个变量,获取一个指针,就像你对其他数据所做的那样。

【讨论】:

以上是关于尝试将数字写入二进制文件时引发异常的主要内容,如果未能解决你的问题,请参考以下文章

每当我尝试将数字数据写入我的 .txt 文件时,它都会引发错误

尝试使用 FileLock、Python 写入文件时权限被拒绝

紧急求助!!!JAVA语言下如何将二进制数字写入文件然后读出来

将结构写入二进制文件 C++ 时遇到问题

从 mysql 数据库中检索图像时引发异常

python--17 文件