【问题标题】:Allocate memory and store metadata分配内存并存储元数据
【发布时间】:2021-05-11 12:57:56
【问题描述】:

假设,我想分配一块内存并在该块前面存储一些元数据。 为此,我想出了这个:

#include <stdlib.h>
#include <stddef.h>

typedef struct metadata_s{
    char someMetaData[3];
}metadata_t;

typedef struct mem_block_s{
    metadata_t metadata;
    //Insert padding so 'data' has fundamental alignment
    char padding[sizeof(max_align_t) == sizeof(metadata_t) ? 0 : sizeof(max_align_t) - (sizeof(metadata_t)) % sizeof(max_align_t)];
    char data[];
}mem_block_t;

void* allocateMemory(size_t size){
    mem_block_t* newMemBlock = malloc(sizeof(mem_block_t) + size);
    if(newMemBlock != NULL){
        return(newMemBlock->data);
    }
    return(NULL);
}

int main(void){
    double* doubleArray = allocateMemory(100 * sizeof(double));
    if(doubleArray != NULL){
        doubleArray[0] = 1.0f;
    }
}

这有多个问题:

  • C 只保证在结构的开头没有填充,mem_block_s 结构内可能有额外的填充
  • 最终,我返回并将指向 char 数组的指针分配给(在这种情况下)double 指针(我可以这样做吗?)

相反,我可以做类似的事情

typedef struct mem_block_s{
    metadata_t metadata;
    void* data;
}mem_block_t;

并分别为data 分配内存,但是只要给定data 指针,我将很难访问元数据。

什么是正确的 C 方法来做这样的事情?

【问题讨论】:

  • 去掉padding成员,将data成员改为char _Alignas(max_align_t) data[];。这既简化了代码,又解决了编译器假设插入不必要的填充的问题。
  • Re“(我可以这样做吗?)”:是的,也不是。可以说,您可以通过将其写入为double 来为内存创建一个有效的类型,但该标准并没有以一种正式的方式来说明这一点。我希望它不会成为当前编译器的问题。 (也可以,因为 C 标准几乎没有禁止;您允许这样做。您的问题实际上应该是行为是否已定义。)
  • 谢谢,我忘了 _Alignas。这简化了事情。

标签: c dynamic-memory-allocation


【解决方案1】:

作为一个忠实的 gcc 用户,我会使用零大小数组的零联合。

typedef struct metadata_s{
    char someMetaData[3];
}metadata_t;

typedef union
{
    char c[0];
    unsigned char uc[0];
     /* ... */
     double dbl[0];
}DATA_t;

typedef struct mem_block_s{
    metadata_t metadata;
    //Insert padding so 'data' has fundamental alignment

    DATA_t data[];
}mem_block_t;

void* allocateMemory(size_t size){
    mem_block_t* newMemBlock = malloc(sizeof(mem_block_t) + size);
    if(newMemBlock != NULL){
        return(newMemBlock->data);
    }
    return(NULL);
}

int main(void){
    DATA_t* doubleArray = allocateMemory(100 * sizeof(double));
    if(doubleArray != NULL){
        doubleArray -> dbl[0] = 1.0f;
    }
}

但我知道这不是很便携 - 可能无法使用

【讨论】:

  • 是的,但我有点想避免 gcc 扩展,并有一些东西只返回一个与 malloc 返回的指针兼容的指针。
猜你喜欢
  • 2013-05-29
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 2014-11-24
  • 1970-01-01
  • 2013-01-03
  • 2015-03-25
  • 1970-01-01
相关资源
最近更新 更多