我刚刚目睹了该std::ofstream::write
方法的疯狂怪异行为。我正在编写自己的 Windows BMP 文件格式处理方法,其中包括将位图保存到文件中——作为介绍。这里有一个子程序负责写入位图文件的头部,给定std::ofstream
对象的引用。
void
BitmapFileManager::FileHeader::save(std::ofstream& fout) const
{
word w;
dword dw;
char const* cw = reinterpret_cast<char*>(w );
char const* cdw = reinterpret_cast<char*>(dw);
uint const sw = sizeof(w );
uint const sdw = sizeof(dw);
fout.write(&sig1, sizeof(sig1));
fout.write(&sig2, sizeof(sig2));
dw = toLittleEndian(size); fout.write(cdw, sdw);
w = toLittleEndian(reserved1); fout.write(cw , sw );
w = toLittleEndian(reserved2); fout.write(cw , sw );
dw = toLittleEndian(pixelsOffset); fout.write(cdw, sdw);
}
这里唯一要标记的是sig1
andsig2
都是char
, sizeof(word) = 2
and类型sizeof(dword) = 4
。此代码应导致两次将一个字节写入文件,然后是一个四字节块,两个两字节块,最后是一个四字节块。
看一下结果的十六进制转储(后面还有一些东西,但忽略它们):
00000000 42 4d 42 4d 00 00 00 05 00 05 42 4d 00 00 28 00 |BMBM......BM..(.|
sig1
andsig2
被打印两次,正确的值实际上是B
and M
,在开头并且出于某种奇怪的原因也在第 11 和第 12 字节。我不承认这一行中的其他价值观。但是看看如果我在每个之间添加一个调试字节会发生什么write
:
void
BitmapFileManager::FileHeader::save(std::ofstream& fout) const
{
word w;
dword dw;
char const* cw = reinterpret_cast<char*>(w );
char const* cdw = reinterpret_cast<char*>(dw);
uint const sw = sizeof(w );
uint const sdw = sizeof(dw);
char nil = '*';
fout.write(&sig1, sizeof(sig1));
fout.write(&nil, sizeof(nil));
fout.write(&sig2, sizeof(sig2));
fout.write(&nil, sizeof(nil));
dw = toLittleEndian(size); fout.write(cdw, sdw);
fout.write(&nil, sizeof(nil));
w = toLittleEndian(reserved1); fout.write(cw , sw );
fout.write(&nil, sizeof(nil));
w = toLittleEndian(reserved2); fout.write(cw , sw );
fout.write(&nil, sizeof(nil));
dw = toLittleEndian(pixelsOffset); fout.write(cdw, sdw);
fout.write(&nil, sizeof(nil));
}
十六进制转储变为
00000000 42 2a 4d 2a 6c 3b 78 a0 2a 00 05 2a 00 05 2a 6c |B*M*l;x?*..*..*l|
00000010 3b 78 a0 2a 28 00 00 00 28 00 00 00 28 00 00 00 |;x?*(...(...(...|
似乎完全没问题。没有重复项,并且*
将字符串1-1-4-2-2-4
按应有的方式划分为字节序列。有人可以帮我找出原因吗?它是编译时的错误吗?我gcc version 4.0.1 (Apple Inc. build 5490)
在带有 -O2 的 Mac OS X Leopard 上使用,但其他级别没有改变任何东西。