C语言非Windows环境读取BMP文件头出现biSize数值过大问题
问题原因与解决方案
你验证得到bfType字段正常的结果刚好可以佐证核心问题为结构体对齐填充,该字段是结构体首个成员,不受填充影响所以读取正确,后续成员全部因为字节错位读取失败。
1. 修复结构体字节对齐问题
C编译器默认开启内存对齐优化,会在结构体成员之间插入填充字节,你定义的BITMAPFILEHEADER实际大小为16字节,而非预期的14字节,fread多读了2字节,导致后续INFOHEADER的读取全部错位。
不同编译器的关闭对齐写法:
GCC/Clang环境
给结构体添加packed属性:
typedef struct __attribute__((packed)) tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef struct __attribute__((packed)) tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;
MSVC环境
使用预编译指令指定对齐粒度:
#pragma pack(1) // 按1字节对齐,取消填充 typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; #pragma pack() // 恢复默认对齐
2. 修复基础数据类型定义
非Windows系统下unsigned long长度随系统位数变化,64位系统下为8字节,和Windows下固定4字节的DWORD/LONG定义不符,直接使用C标准库的固定长度整数类型即可:
// 头文件添加这两个包含 #include <stdint.h> #include <inttypes.h> // 替换原有类型定义 typedef uint32_t DWORD; typedef int32_t LONG; typedef uint16_t WORD; typedef uint8_t BYTE;
3. 修复输出格式化符
使用匹配固定长度类型的格式化符,避免输出错误:
// 替换原有printf语句 printf("size: %" PRIu32 "\n", dib.biSize);
修复后正常的BITMAPINFOHEADER的biSize字段值应为40,符合标准BMP格式定义。
内容的提问来源于stack exchange,提问作者Navxihziq
相关产品推荐
相关产品推荐

