【发布时间】:2014-02-03 12:11:39
【问题描述】:
我正在为 C 中的各种数学计算编写一个库。其中一些需要一些“临时”空间——用于中间计算的内存。所需空间取决于输入的大小,因此不能静态分配。该库通常用于使用相同大小的输入执行相同类型计算的多次迭代,因此我不希望每次调用都在库中使用malloc 和free;一次分配足够大的块,将其重新用于所有计算,然后释放它会更有效。
我的预期策略是请求一个指向单个内存块的void 指针,可能附带一个分配函数。说,像这样:
void *allocateScratch(size_t rows, size_t columns);
void doCalculation(size_t rows, size_t columns, double *data, void *scratch);
这个想法是,如果用户打算做几个相同大小的计算,他可以使用 allocate 函数来抓取一个足够大的块,然后使用同一块内存来执行每个计算输入。 allocate 函数不是绝对必要的,但它简化了接口,使将来更容易更改存储需求,而不需要库的每个用户确切知道需要多少空间。
在许多情况下,我需要的内存块只是double 类型的大型数组,没有问题。但在某些情况下,我需要混合数据类型——比如一个双精度块和一个整数块。我的代码需要是可移植的,并且应该符合 ANSI 标准。我知道可以将 void 指针转换为任何其他指针类型,但如果我尝试对两种类型使用相同的块,我会担心对齐问题。
所以,具体的例子。假设我需要 3 个 doubles 和 5 个 ints 块。我可以像这样实现我的功能吗:
void *allocateScratch(...) {
return malloc(3 * sizeof(double) + 5 * sizeof(int));
}
void doCalculation(..., void *scratch) {
double *dblArray = scratch;
int *intArray = ((unsigned char*)scratch) + 3 * sizeof(double);
}
这合法吗?在此示例中对齐可能正常,但如果我切换它并首先采用 int 块和第二个 double 块,这将改变 double 的对齐方式(假设为 64 位双精度和 32 位整数)。有一个更好的方法吗?还是我应该考虑一种更标准的方法?
我最大的目标如下:
- 如果可能的话,我想使用单个块,这样用户就不必处理多个块或需要不断变化的块数。
- 我希望该块是
malloc获得的有效块,因此用户可以在完成后调用free。这意味着我不想创建一个小的struct,它具有指向每个块的指针,然后分别分配每个块,这需要一个特殊的销毁函数;如果这是“唯一”的方式,我愿意这样做。 - 算法和内存要求可能会发生变化,因此我尝试使用 allocate 函数,以便将来的版本可以为可能不同类型的数据获得不同数量的内存,而不会破坏向后兼容性。
也许这个问题在 C 标准中得到了解决,但我一直没能找到它。
【问题讨论】:
-
第一个例子没问题,第二个例子你必须填充到下一个可被 sizeof(double) 整除的最近地址。
-
是的,这正是我所期望的。可以保证可以接受吗?似乎尝试手动确保正确对齐可能不值得。
-
是的,没错。这样你只会浪费最后一个成员的记忆。如果您使用工会,您将浪费每个成员。只要确保您知道 int 结束和 double 开始的位置。
-
(注意:您不能对
void*执行算术运算,因此在您的scratch + N*sizeof(double)中您应该将scratch 转换为char*,或double*,然后只添加N,最后将其重新转换为int* -
@ShinTakezou 哦,是的,很好!显然,我没有编译我的示例代码:)。
标签: c memory dynamic-memory-allocation memory-alignment