1

我有以下代码。该文件包含一个位图图像,第一个字节是 0x424d。我希望第一个 printf 打印 BM,而不是打印 BM??。

此外,第二个 printf 打印 10,我希望它是一个更大的数字,因为文件大于 10 个字节。

fp = fopen("input.bmp", "r");
bmp_header_p = malloc(sizeof(bmp_header_t));

rewind(fp);
fread(bmp_header_p, sizeof(char), 14, fp);

printf("magic number = %s\n", bmp_header_p->magic);
printf("file size = %" PRIu32 "\n", bmp_header_p->filesz);

typedef struct {
uint8_t magic[2];   /* the magic number used to identify the BMP file:
                     0x42 0x4D (Hex code points for B and M).
                     The following entries are possible:
                     BM - Windows 3.1x, 95, NT, ... etc
                     BA - OS/2 Bitmap Array
                     CI - OS/2 Color Icon
                     CP - OS/2 Color Pointer
                     IC - OS/2 Icon
                     PT - OS/2 Pointer. */
uint32_t filesz;    /* the size of the BMP file in bytes */
                     of the byte where the bitmap data can be found. */
} bmp_header_t;
4

4 回答 4

2

%s用于以空字符结尾的字符串。magic只是一个 2 个字节的数组,而不是一个字符串。

printf("magic number = %c%c\n", bmp_header_p->magic[0], bmp_header_p->magic[1]);
于 2013-06-22T19:55:44.757 回答
2

你有几个问题:

  1. magic编译器可能会在和filesz成员之间的数据结构中添加填充。您可以使用编译器特定的扩展,例如编译指示和属性来避免这种行为并获得打包结构(Visual StudioGCC)。但是这些不是便携式的,如果可能的话应该避免。
  2. 格式说明符需要一个以%snull 结尾的字符串,但您传递的字符串没有终止。您应该改为使用说明符,例如%.2s最多打印 2 个字符。
  3. 位图文件格式为 little-endian。如果你的计算机也是 little-endian,那么它看起来可以正常工作,但是当你编译成 big-endian 架构时,你会发现它会突然停止工作。您必须对任何多字节值进行端序交换,例如filesz在大端序平台上。
  4. 调用 torewind(3)不是必需的——文件指针保证在您打开文件后位于文件的开头。

有很多方法可以解决问题(1);有无数关于如何在 C 中正确进行序列化的文章和答案。我建议您单独阅读每个成员,这样您就不必担心编译器如何布置您的结构,并且它将完全可移植到所有人平台。

此外, C 标准保证为 1,因此很少需要在例如函数参数中sizeof(char)显式写出.sizeof(char)fread(3)

于 2013-06-22T20:00:39.640 回答
1

当您将某些内容打印为字符串时,该printf函数将继续运行,直到它到达一个空终止符。因此,尽管前两个字节可能代表BM,但您没有做任何事情来确保打印停止在那里。除非内存中的下一个字节是'0'printf否则将继续寻找字符并打印它们。事实证明,接下来的两个是“不可打印的”,并导致??. 在那之后,可能会有一个'0'输出停止......

至于第二点 - 格式规范说整数以小端格式存储。您没有做任何事情来确保您以这种方式解释数字 - 实际上您可能正在使用大端机器,在这种情况下,数字10实际上是 10*256*256*256 = 167772160。当然有不能保证结构中的数字实际上与您的想法一致 - 可能存在一些(编译器、平台)特定的填充。然后是当二进制文件以“r”而不是“rb”模式打开时会发生什么的问题......

这是解决这些问题的一种可能方法:

#define HEADER_SIZE 14
#define SIZE_START 2

fp = fopen("input.bmp", "r");
bmp_header_p = malloc(HEADER_SIZE);

fread(bmp_header_p, HEADER_SIZE, 1, fp);

printf("magic number = %c%c\n", bmp_header_p[0], bmp_header_p[1]);

long int fileSize=0, ii;
for(ii=0;ii<4;ii++) fileSize+=256*fileSize + bmp_header+p[ii + SIZE_START];

printf("file size = %ld\n", fileSize);
于 2013-06-22T19:56:32.630 回答
0

只需填充一个 3 char 空终止数组。

char label[] ="00\0"; label[0] =magic[0]; label[1] =magic[1]; prints("%s\n", label );

于 2013-06-22T20:35:24.270 回答