可以在 malloc 缓冲区上执行整数运算(例如加法或减法)吗?

Can integer operations (eg addition or subtraction) be performed on malloc buffers?

为了了解 JPEG 压缩,我下载了一个我一直在研究的简单 BMP/JPEG encoder。我有几个问题,希望有人能帮助我。我不是训练有素的计算机科学家,只是业余爱好的程序员。感谢您的帮助。

以下代码读取位图,为简洁起见,我省略了一些信息。我知道位图 header 被写成一个结构,所以组件可以直接读取到变量而无需迭代。

BYTE 是 uint8_t

的类型定义
    int bmp_load(BMP *pb, char *file)
{
    BMPFILEHEADER header = {0};
    FILE         *fp     = NULL;
    BYTE         *pdata  = NULL;
    int           i;

    fp = fopen(file, "rb");
    if (!fp) return -1;

    fread(&header, sizeof(header), 1, fp);
    pb->width  = header.biWidth;
    pb->height = header.biHeight;
    pb->stride = ALIGN(header.biWidth * 3, 4);
    pb->pdata  = malloc(pb->stride * pb->height);// allocate a byte for each element of bitmap?
    if (pb->pdata) {
        pdata  = (BYTE*)pb->pdata + pb->stride * pb->height; // Title question: Cast pdata as uint8_t buffer but what is the addition for? I think it has to do with padding a BMP file.  Without addition there is a bus error: 10 
        for (i=0; i<pb->height; i++) {
            pdata -= pb->stride; // What is the subtraction for? 
            fread(pdata, pb->stride, 1, fp);
        }
    }

    fclose(fp);
    return pb->pdata ? 0 : -1; // If pdata was being modified in the for loop, why is pb->pdata returned? 
}

我将我的问题作为代码中的注释,并粘贴在下面。 加法是为了什么?我认为这与填充 BMP 文件有关。不加就有总线错误:10

    pdata  = (BYTE*)pb->pdata + pb->stride * pb->height;

减法是为了什么?

    pdata -= pb->stride;

最后,为什么返回的是 pb->pdata 而实际上是在代码中修改的 pdata?

这是将数据从文件 file 读取到缓冲区 pb->pdata,大小为 pb->stride 的块, 以相反的顺序 。块数为pb->height.

指针pdata用于指示下一个块在缓冲区中的位置。由于缓冲区的总大小为 pb->stride * pb->height,行

pdata  = (BYTE*)pb->pdata + pb->stride * pb->height;

pdata 设置为指向缓冲区的末尾 pb->pdata (即指向最后一个元素之后的元素)。当在循环的第一次迭代中从 pdata 中减去 pb->stride 时,pdata 将指向第一个块要放置的位置,填充 缓冲区的 last pb->stride 字节。在连续的迭代中,pdata 继续递减,以相反的顺序将块写入缓冲区,直到最后一个块被放置在缓冲区的开头 pb->pdata.

如果省略初始加法,则 pdata 将开始指向缓冲区的 beginning,然后减法会使它指向 before 缓冲区的开始。然后尝试在该位置读取将越界,这不足为奇地导致崩溃。

请注意,该函数实际上并不是 returning pb->pdata,而是 pb->pdata ? 0 : -1。这是使用 C 三元运算符 并表示如果 pb->pdata 为非 NULL,则 return 0,否则 return -1。现在 pb->pdata 只有在之前的 malloc 失败(即没有内存可用)时才会为 NULL,在这种情况下,整个读取循环将被 if (pb->pdata) 跳过。所以这实际上是 returning 0 表示成功,-1 表示失败,这也是一个常见的习语。

这里是对函数的重写,可能更容易理解。

int bmp_load(BMP *pb, char *file)
{
    FILE* = fopen(file, "rb");
    if (!fp) return -1;

    BMPFILEHEADER header;
    fread(&header, sizeof(header), 1, fp);
    pb->width = header.biWidth;
    pb->height = header.biHeight;
    pb->stride = ALIGN(header.biWidth * 3, 4);
    pb->pdata = malloc(pb->stride * pb->height);

    if (!pb->pdata) return -1;

    for (int i = pb->height - 1; i >= 0; i--) {
        BYTE* pdata_current_row = pb->pdata + pb->stride * i;
        fread(pdata_current_row, pb->stride, 1, fp);
    }

    fclose(fp);
    return 0;
}

for 循环 i 减少,因为 pixels are usually stored "bottom-up"(至少在 BMP 中)。