我正在尝试创建.BMP文件.根据我的定义,BMP头是54个字节长.代码编译和一切,但在尝试打开文件时,我得到"错误的标题格式"错误.
如果我做一个sizeof(structtype)我得到56个字节而不是定义的54 - 如果我用值初始化一个结构,然后做一个sizeof(newStruct),我得到8个字节.因为我需要将54个字节写入文件,所以这很糟糕.
有没有办法让GCC不以这种方式改变结构大小?
这是结构的定义:
typedef struct
{
uint16_t typeSignature; // = "BM"
uint32_t filesize; //filesize in Bytes
uint32_t reserved; // = 0 for this program
uint32_t headerOffset; // = 54
} BmpFileHeader;
typedef struct
{
uint32_t infoHeaderSize; //size of header in byte. ( = 40)
uint32_t Width; //width of file in pixels
uint32_t Height; // height of file in pixels
uint16_t Colors; //colorbits per pixel (24 for 3byte RGB)
uint16_t bitsPerPixel;
uint32_t Compression; //compression mode; 0 for uncompressed.
uint32_t SizeImg; //if biCompress = 0, =0. Else: filesize.
uint32_t xPelsPerMeter; // for output device;
uint32_t yPelsPerMeter; // 0 for this program
uint32_t ColorsUsed; // Colours used; = 0 for all
uint32_t ColorsImportant; // num. of used colours, 0 for all
} BmpInfoHeader;
typedef struct
{
BmpFileHeader fileheader;
BmpInfoHeader infoheader;
} bitmapHead; // sizeof = 56
Run Code Online (Sandbox Code Playgroud)
这里初始化一个新标题的函数:
bitmapHead* assembleHeader(int compCount)
{
bitmapHead* newHeader = (bitmapHead*) calloc(1, 54);
newHeader->fileheader.typeSignature = 0x4D42;
newHeader->fileheader.filesize = (compCount*100*51*3 + 54);
newHeader->fileheader.reserved = 0;
newHeader->fileheader.headerOffset = 54;
newHeader->infoheader.infoHeaderSize = 40;
newHeader->infoheader.Width = 100*compCount;
newHeader->infoheader.Height = 51;
newHeader->infoheader.Colors = 1;
newHeader->infoheader.bitsPerPixel = 21;
newHeader->infoheader.Compression = 0;
newHeader->infoheader.SizeImg = compCount*100*51*3;
newHeader->infoheader.xPelsPerMeter = 0;
newHeader->infoheader.yPelsPerMeter = 0;
newHeader->infoheader.ColorsUsed = 0;
newHeader->infoheader.ColorsImportant = 0;
printf("%lu \n", sizeof(newHeader)); // This gives me 8.
return newHeader;
}
Run Code Online (Sandbox Code Playgroud)
这是"不要那样做"的情况.具体而言,永远不要尝试布局struct与外部规范定义的字节模式匹配的C. C标准对与此合作并不感兴趣,虽然有些编译器试图使其成为可能,但它比它的价值更麻烦.(阅读Ada表示条款,如果您有兴趣了解认真解决这个问题的语言.)
您可以定义a struct来表示内存中的BMP头,但是您从磁盘读取/写入的内容应该是一个数组uint8_t.雅莉.您必须编写函数以在内存中表示和磁盘表示之间显式转换.这些也是进行任何必要检查和处理字节序的好地方.
BmpFileHeader的工作示例:
// Fixed fields not represented in in-memory header.
typedef struct
{
uint32_t filesize; // total size of file in bytes
uint32_t headerOffset; // offset from beginning of file to end of headers
// (normally 54)
} BmpFileHeader;
#define BMP_FILE_HEADER_MAGIC_1 0
#define BMP_FILE_HEADER_MAGIC_2 1
#define BMP_FILE_HEADER_FILESIZE 2
#define BMP_FILE_HEADER_RESERVED 6
#define BMP_FILE_HEADER_HDROFF 10
#define BMP_FILE_HEADER_SIZE 14
typedef uint8_t BmpFileHeaderOnDisk[BMP_FILE_HEADER_SIZE];
uint32_t
le32_to_cpu(uint8_t *p)
{
return ((((uint32_t)p[0]) << 0) |
(((uint32_t)p[1]) << 8) |
(((uint32_t)p[2]) << 16) |
(((uint32_t)p[3]) << 24));
}
// Returns true if header is successfully parsed.
bool
load_bmp_file_header(BmpFileHeaderOnDisk ondisk, BmpFileHeader *inmem)
{
if (ondisk[BMP_FILE_HEADER_MAGIC_1] != 'B' ||
ondisk[BMP_FILE_HEADER_MAGIC_2] != 'M' ||
le32_to_cpu(ondisk + BMP_FILE_HEADER_RESERVED) != 0)
return false; // not a BMP file
inmem->filesize = le32_to_cpu(ondisk + BMP_FILE_HEADER_FILESIZE);
inmem->headerOffset = le32_to_cpu(ondisk + BMP_FILE_HEADER_HDROFF);
return true;
}
Run Code Online (Sandbox Code Playgroud)
相反的方式,以及"信息"标题的处理,留下练习.