在C中创建BMP头(不能限制2个字节的字段)

时间:2015-06-21 16:54:33

标签: c bmp

我的基础是:

https://en.wikipedia.org/wiki/BMP_file_format

我想在C中从头开始创建BMP图像。

#include <stdio.h>
#include <stdlib.h>

typedef struct HEADER {
    short FileType;
    int FileSize;
    short R1;
    short R2;
    int dOffset;
} tp_header;

int main () {
    FILE *image;

    image = fopen("test.bmp", "w");

    tp_header bHeader;

    bHeader.FileType = 0x4D42;
    bHeader.FileSize = 70;
    bHeader.R1 = 0;
    bHeader.R2 = 0;
    bHeader.dOffset = 54;

    fwrite(&bHeader, sizeof(struct HEADER), 1, image);

    return 0;
}

我应该得到输出文件:

42 4D 46 00 00 00 00 00 00 00 36 00 00 00

但我得到了:

42 4D 40 00 46 00 00 00 00 00 00 00 36 00 00 00

首先它应该只包含14个字节。那个“40 00”毁了这一切。这是在C中设置标题的方法吗?我怎么能限制输出的字节大小?

2 个答案:

答案 0 :(得分:1)

struct可能在字段之间包含填充字节,以将下一个字段与某些地址偏移对齐。这些填充字节的值是不确定的。典型的布局可能如下所示:

struct {
    uint8_t field1;
    uint8_t <padding>
    uint8_t <padding>
    uint8_t <padding>
    uint32_t field2;
    uint16_t field3;
    uint8_t <padding>
    uint8_t <padding>
};

<padding>刚刚由编译添加;您的程序无法访问它。 这只是一个例子。实际填充可能不同,并由您的体系结构的ABI(CPU / OS /工具链)定义。

此外,较大类型的字节存储在内存中的顺序( endianess )取决于体系结构。但是,由于文件需要特定的字节顺序,因此可能还需要修复。

一些 - 但不是全部 - 编译器如果指定structpacked(避免填充),仍然无法帮助解决字节问题。< / p>

最好是通过轮班正确地序列化结构并存储到uint8_t - 数组:

#include <stdint.h>

/** Write an uint16_t to a buffer.
 *
 *  \returns The next position in the buffer for chaining.
 */
inline uint8_t *writeUInt16(uint8_t *bp, value)
{
    *bp++ = (uint8_t)value;
    *bp++ = (uint8_t)(value >> 8);
    return bp;
}

// similar to writeUInt16(), but for uint32_t.
... writeUInt32( ... )
    ...

int main(void)
{
    ...

    uint8_t buffer[BUFFER_SIZE], *bptr;

    bptr = buffer;
    bptr = writeUInt16(bptr, 0x4D42U);    // FileType
    bptr = writeUInt32(bptr, 70U);        // FileSize
    ...

}

这将使用标题字段填充buffer。必须根据您要创建的标头设置BUFFER_SIZE。存储完所有字段后,将buffer写入文件。

声明函数inline提示一个好的编译器来为常量创建几乎最优的代码。

另请注意,short等的大小不固定。使用stdint.h类型是您需要定义大小的类型。

答案 1 :(得分:0)

问题是您的结构是对齐的。你应该把它写成

mydata %>% 
  filter(measure == "pagesubmit") %>%
  .$value %>% ## extract a character vector of values
  as.numeric() %>% ## convert it to numeric
  mean() ## calculate the mean

仅供您了解 - 默认情况下优化原因的编译器会将其列为:

#pragma pack(push, 1)
typedef struct HEADER {
    short FileType;
    int FileSize;
    short R1;
    short R2;
    int dOffset;
} tp_header;
#pragma pack(pop)

但你实际上又犯了另一个错误:typedef struct HEADER { short FileType; char empty1; //inserted by compiler char empty2; //inserted by compiler int FileSize; short R1; short R2; int dOffset; } tp_header; 。即取决于平台整数可以是8个字节。重要的是,在这种情况下,您必须使用int32_t from cstdint

等类型