(我这样做是为了一个个人项目--只是为了学习指针/引用/内存管理之类的东西如何在C语言中工作.我想"不作弊",也就是说,没有任何超抽象库或语言的帮助.因此,C语言是首选语言.)
很简单,我正在try 将带有原始数据的位图文件的头文件读入传递给函数的 struct 实例.首选工具-ChatGPT和GCC推荐的fread(),因为这是您在Linux Ubuntu终端上通常使用的.
以下是传统的54字节头BMP格式的代码(请注意,字节填充问题已得到处理):
#ifndef BMPHEADER_H
#define BMPHEADER_H
#include <stdint.h> // For fixed-width types
#pragma pack(push, 1) // Ensure that structure is packed without padding
typedef struct {
uint16_t signature; // BM
uint32_t fileSize;
uint16_t reserved1;
uint16_t reserved2;
uint32_t dataOffset;
uint32_t headerSize;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bitsPerPixel;
uint32_t compression;
uint32_t rawBmpSize;
uint32_t horizRes;
uint32_t vertRes;
uint32_t numColors;
uint32_t numImptColors;
} BmpHeader;
#pragma pack(pop)
#endif
下面是实例化包含头的 struct 并提供令人满意的结果的代码:
void run_core_funcs(void)
{
printf("Running core OCR and I/O functions ...\n");
ProcList pm;
BmpHeader bh;
get_fname(pm.fname);
FILE * src = fopen(pm.fname, "rb");
fread(&bh, sizeof(bh), 1, src);
printf("Sig: %x \n", bh.signature);
printf("File size: %x \n", bh.fileSize);
printf("Res 1: %x \n", bh.reserved1);
printf("Res 2: %x \n", bh.reserved2);
printf("Offset: %x \n", bh.dataOffset);
fclose(src);
get_img_props(&pm, &bh);
请注意,我正在调用一个不同的函数,并通过它们的指针传递处理规范管理器和位图标头(因为C没有用于按引用传递的构造).这就是事情变得有趣的地方.
void get_img_props(ProcList * pm, BmpHeader * imgHdr)
{
printf("Caching image data from %s ...\n", pm->fname);
FILE * src = fopen(pm->fname, "rb");
fread(imgHdr, sizeof(imgHdr), 1, src);
printf("Sig: %x \n", imgHdr->signature);
printf("File size: %x \n", imgHdr->fileSize);
printf("Res 1: %x \n", imgHdr->reserved1);
printf("Res 2: %x \n", imgHdr->reserved2);
printf("Offset: %x \n", imgHdr->dataOffset);
fclose(src);
是的,重复代码,只是为了确保一切正常.
下面是"外部"和"内部"两个函数的满意结果.(是的,我知道这些字段表明文件大小、数据偏移量和信息头大小应该非常大,但这不是重点.)
Sig: 4d42
File size: 7e98a
Res 1: 0
Res 2: 0
Offset: 8a
然而,...一旦我注释掉run_core_uncs()中的原始数据检索代码,通过它们的指针传递 struct 实例,并且只在get_img_props()中执行原始数据检索,我就得到了一些不同的东西:
结果:
Sig: 4d42
File size: 7e98a
Res 1: 0
Res 2: 3
Offset: 0
为什么会这样呢?与其说我做错了什么,不如说我更倾向于相信C中指针的工作方式或GCC处理事物的方式存在固有的错误实现.但我知道什么呢.
我在不同的平台(Google、SO、this Reddit one is not particularly helpful)上做了一些研究,我得到的唯一结果是与指针和引用的混淆有关的通用命中,以及对内存开销的担忧等.ChatGPT也没有真正做任何帮助,提出了各种不同的要点,都是我的错,我应该判断我清晰的工作中是否有错误,并说明我已经考虑到的所有问题-将地址传递给 struct 对象的质量、数据对齐要求等.还有一个提醒:我正在使用GCC.