立即分配指针和指针

时间:2015-03-16 22:33:54

标签: c allocation

如果我想减少malloc() s(特别是如果数据很小并经常分配)我想立即分配指针和指针。

如果您假设以下内容:

struct entry {
    size_t      buf_len;
    char        *buf;
    int         something;
};

我想以下列方式分配内存(不要在这里关心错误检查):

size_t buf_len  = 4;                // size of the buffer
struct entry *e = NULL;

e = malloc( sizeof(*e) + buf_len ); // allocate struct and buffer
e->buf_len  = buf_len;              // set buffer size
e->buf      = e + 1;       // the buffer lies behind the struct

这甚至可以扩展,以便一次分配整个数组。

您如何评估以下方面的技术:

  • 可移植性
  • 可维护性/可扩展性
  • 性能
  • 可读性

这合理吗?如果可以使用,有没有关于如何设计可能的接口的想法?

5 个答案:

答案 0 :(得分:2)

您可以使用灵活的数组成员而不是指针:

struct entry {
    size_t      buf_len;
    int         something;
    char        buf[];
};

// ...
struct entry *e = malloc(sizeof *e  + buf_len);
e->buf_len = buf_len;

便携性和性能都很好。可读性:不完美但足够好。

可扩展性:您不能一次将它用于多个成员,您必须回退到显式指针版本。此外,显式指针版本意味着如果将其用于没有1对齐的类型,则必须进行粘贴以确保正确对齐。

如果您正在认真思考这个问题,我会考虑重新审视整个数据结构的设计,看看是否有其他方法可以做到这一点。 (也许这种方式实际上是最好的方式,但首先要好好考虑一下)。

答案 1 :(得分:1)

关于可移植性,我不知道任何问题,只要通过适当的sizeof()调用找到大小,就像在代码中一样。

关于可维护性,可扩展性和可读性,您当然应该在一个评论很好的函数中包装分配和解除分配。打电话给......

entry *allocate_entry_with_buffer();
void deallocate_entry_with_buffer(entry **entry_with_buffer);

...不需要知道如何实际处理内存的实现细节。人们经常使用自定义分配器和内存池等奇怪的东西。

至于速度,这肯定比制作大量小额分配更快。我曾经用类似的策略分配整个二维矩阵......

答案 2 :(得分:1)

它应该可以工作,但事实上你正在使用一个无用的间接指针。 Windows API(例如)对可变大小的结构使用另一种方法:变量大小缓冲区在结构中是最后一个,并声明为char buf[1]

您的结构将成为:

struct entry {
    size_t      buf_len;
    int         something;
    char        buf[1];
};

分配是(仍然没有错误检查):

size_t buf_len  = 4;                // size of the buffer
struct entry *e;

e = malloc( sizeof(*e) + buf_len  - 1); // struct already has room for 1 char
e->buf_len  = buf_len;              // set buffer size

所有e.buf都保证是一个大小为buf_len的字符数组。

这样可以确保即使变量部分不是字符数组而是int,long或任何数组,最后一个元素也是一个正确类型和大小为1的数组。

答案 3 :(得分:0)

对我来说似乎很好 - 尽管发表评论

或者你可以这样做 - 这很常见

struct entry {
    size_t      buf_len;
    int         something;
    char        buf;
};

即使struct本身可变长度。并做

size_t buf_len  = 4;                // size of the buffer
struct entry *e = NULL;
//  check that it packs right
e = malloc(sizeof(size_t) + sizeof(int) + buf_len ); // allocate struct and buffer
e->buf_len  = buf_len;              // set buffer size
...... later
printf(&e.buf);

答案 4 :(得分:0)

对于初学者来说,这一行:

e->buf      = e + sizeof(*e);       // the buffer lies behind the struct

应该是:

e->buf      = e + 1;       // the buffer lies behind the struct

这是因为e + 1将等于结构末尾的地址。正如你所知,它只是结构中的字节数等于指针中的字节数。

而且,是的,这是合理的。但是,我更喜欢这种方法:

struct entry {
    size_t      buf_len;
    int         something;
    char        buf[1];
};

这样,你就不会乱用指针。只需根据需要添加多个字节,它们就会增加buf数组的大小。

注意:我使用类似于此的方法编写了一个文本编辑器,但使用了Microsoft c ++扩展,允许我将最后一个成员声明为char buf[]。所以它是一个空数组,与我分配的额外字节数一样长。