使用 fread() 读取 BMP 的文件头
Posted
技术标签:
【中文标题】使用 fread() 读取 BMP 的文件头【英文标题】:Reading Fileheader of a BMP with fread() 【发布时间】:2014-10-24 11:44:54 【问题描述】:我正在使用 Linux 尝试加载 BMP 的标头。我已经查看了标题,应该得到文件前两个字符的“BM”。我一直在使用的代码:
FILE* fp = fopen(filename, "r");
if(!fp)
std::cout << "Unable to open file : " << filename << std::endl;
return NULL;
char* headerField = new char[2];
fread(headerField, 2, sizeof(char), fp);
std::cout << headerField << std::endl;
if(strcmp(headerField, "BM"))
delete [] headerField;
std::cout << "File is not a bitmap" << std::endl;
fclose(fp);
return NULL;
else
std::cout << "Well done!" << std::endl;
我得到的输出是 BM 后跟一个随机的额外字符,“BM7”、“BMF”、“BM*”...据我了解,fread() 应该读入(在这种情况下)两个个字符的数据,那么这个额外的字符是从哪里来的?
【问题讨论】:
headerfield
的内容没有被明确地以 null 结尾。
不需要动态分配这两个字符。为什么在 C++ 中使用旧的 C I/O 函数?
“旧”C stdio 函数没有任何“错误”。只需正确使用它们和其他语言即可。许多 C++ 程序员完全跳过了 iostream,仍然使用备用 IO 库。
@codenheim 也许使用它并没有错(IMO 值得商榷),但有多种 I/O 风格。还有char*
字符串,它们不是I/O 的一部分,可以避免。人们可以构造一个论点,如果只有 c++ 特定的东西是cout
,那么使用 c++ 是没有意义的。对于给定的示例,它同样有效。
如果使用原始缓冲区,stdio 可能是最合适的。他的错误不是 IO 问题。 iostream 中明确支持与 stdio 同步。
【参考方案1】:
你在大量混合 c 和 c++,我认为这是你一开始就陷入错误的一半原因。
现在,在c
中,出于某种原因,字符串被称为以空字符结尾的字符串。空字符\0
是字符串分隔符的结尾。您正在做的是将两个字节读入headerField
。所以在内存中它看起来像:
|乙|中号 |垃圾|垃圾|垃圾 |
str
家族和其他例程期望char*
字符串以\0
结尾。所以strcmp
和打印在M
之后并没有停止,而是跑到了野外。一个适当的 2 字符 c 样式字符串应该占用 3 个字节,如下所示:
|乙|中号 | 0 |垃圾|垃圾 |
你如何做到这一点我留给你。
我会亲自将代码重写为适当的 c++。
【讨论】:
嗯,有一个问题,有一个解释,一个答案就是一个答案,不管我自己的喜好。我不是做代码审查的人=)。 谢谢,用流重新编写,一切似乎都很好,使用 ifstream::get 的方式几乎相同,它会自动附加一个空终止符。我正在使用上面的代码学习教程,他们完全没有使用这种方法的问题。只是出于好奇,有人知道为什么会这样吗?我能发现我们之间的唯一区别是他使用的是 mac,而我使用的是 Linux,这会影响结果吗? @JamesHodgson 如果一个人得到(不)幸运| garbage | garbage | garbage |
也可能是|0|0|0|
。所以它可以按预期工作。无法保证您在未分配的内存空间中从系统获得什么。至少从标准的角度来看不是。有些系统会将所有内存归零,因此您无法在上一个进程之后恶意读取它。【参考方案2】:
“额外的垃圾”已经存在于内存中。
fread() 完全按照你说的做。它读取 2 个字符。 C 和 C++ 使用以空字符结尾的字符字符串。 cout 将打印缓冲区中的任何内容,直到到达空终止符为止。
你应该创建一个长度大于 2 的字符串,并且你应该设置一个空字符。
【讨论】:
以上是关于使用 fread() 读取 BMP 的文件头的主要内容,如果未能解决你的问题,请参考以下文章