如果我想减少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
这甚至可以扩展,以便一次分配整个数组。
您如何评估以下方面的技术:
这合理吗?如果可以使用,有没有关于如何设计可能的接口的想法?
答案 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[]
。所以它是一个空数组,与我分配的额外字节数一样长。