一段时间以来,我一直在尝试用c++将内存写入文件缓冲区时遇到一个非常奇怪的问题。这个问题只发生在MinGW上。当我在gcc/linux下编译时,一切都很好。
显示问题的调试会话
所以基本上,我正在从内存缓冲区到文件缓冲区编写代码,文件中的二进制表示最终与我写的内存不同。不,文件不会在以后被修改,我通过在关闭文件后使用调试器退出程序来确保这一点。我不知道这样的事情是怎么可能的,我甚至使用valgrind来查看是否有任何内存分配问题,但没有。
我将粘贴一些相关的代码。
/// a struct holding information about a data file
class ResourceFile {
public:
string name;
uint32 size;
char* data;
ResourceFile(string name, uint32 size);
};
ResourceFile::ResourceFile(string name, uint32 size)
: name(name), size(size)
{
// will be free'd in ResourceBuilder's destruction
data = (char*) malloc(size * sizeof(char));
}
/// Build a data resource from a set of files
class ResourceBuilder {
public:
ofstream out; ///< File to put the resource into
vector<ResourceFile> input; ///< List of input strings
/// Add a file from disk to the resource
void add_file(string filename);
/// Create a file that the resource will be written to
void create_file(string filename);
~ResourceBuilder();
};
void ResourceBuilder::create_file(string filename) {
// open the specified file for output
out.open(filename.c_str());
uint16 number_files = htons(input.size());
out.write((char*) &number_files, sizeof(uint16));
foreach(vector<ResourceFile>,input,i) {
ResourceFile& df = *i;
uint16 name_size = i->name.size();
uint16 name_size_network = htons(name_size);
out.write((char*) &name_size_network, sizeof(uint16));
out.write(i->name.c_str(),name_size);
uint32 size_network = htonl(i->size);
out.write((char*) &size_network, sizeof(i->size) );
out.write(i->data, i->size);
}
out.close();
/// todo write the CRC
}
下面是如何首先分配内存的。这是一个可能的错误来源,因为我从其他地方复制了它,而没有费心去详细理解它,但我真的不知道我分配内存的方法是如何导致文件缓冲区输出与我正在编写的内存不同的。
void ResourceBuilder::add_file(string filename) {
// loads a file and copies its content into memory
// this is done by the ResourceFile class and there is a
// small problem with this, namely that the memory is
// allocated in the ResourceFile directly,
ifstream file;
file.open(filename.c_str());
filebuf* pbuf=file.rdbuf();
int size=pbuf->pubseekoff (0,ios::end,ios::in);
pbuf->pubseekpos (0,ios::in);
ResourceFile df(filename,size);
pbuf->sgetn (df.data,size);
file.close();
input.push_back(df);
}
我真的没有主意了。这也不是与我的编译器设置有关的错误,因为其他人在MinGW下编译代码时会得到相同的错误。在这一点上,我能想到的唯一解释是MinGW的文件缓冲区库本身存在错误,但我真的不知道。
您需要以二进制模式打开文件。当您在Windows上以文本模式打开它时,换行(0x0A)将转换为CR/LF对(0x0D, 0x0A)。在Linux上,您不会看到这一点,因为Linux在文本文件中使用单个LF (0x0A)作为行结束符,因此不会进行转换。
将ios::binary
标志传递给ostream::open
方法:
out.open(filename.c_str(), ios::out | ios::binary);
在读取二进制文件时也应该使用这个标志,这样就不会执行相反的转换:
ifstream file;
file.open(filename.c_str(), ios::in | ios::binary);
问题是您以文本模式打开文件!在这种情况下,0x0a
(换行)转换为0x0d0a
(回车换行)。这就是为什么在文件和内存中可以看到不同。
使用out.open(filename.c_str(), ios::binary | ios::out);