如何在C中以可移植的方式管理内存对齐和通用指针算术?

时间:2012-01-23 08:47:55

标签: c pointers memory-management

我必须实现malloc / realloc / free的优化版本(为我的特定应用程序量身定制)。目前代码在特定平台上运行,但我想以可移植的方式编写它,如果可能的话(平台将来可能会改变),或者至少我想将可能的平台差异集中在一个点(可能是.h)。我知道一些问题:

  • 内存对齐方面的差异
  • 适用于“通用”分配的最小内存块大小的差异
  • 指针大小的差异

(我会忽略这里内存分配的基本系统服务的差异,因为在某些嵌入式系统上它们可能完全不可用。让我们假设我们在一个大的预分配内存块上工作,用作“堆” )。

问题:

  • 为了这种目的,C中是否有标准的宏或函数?
  • 我在这份工作中可能面临哪些其他问题?

6 个答案:

答案 0 :(得分:3)

确保适合所有基本类型的对齐的经典方法是定义联​​合:

union alloc_align {
    void *dummy1;
    long long dummy2;
    long double dummy3;
};

...然后确保您发出的地址总是偏离您从系统内存分配器接收的对齐地址的倍数sizeof (union alloc_align)

我认为在K& R中描述了与此类似的方法。

答案 1 :(得分:1)

对齐内存不同于编译器到编译器不幸(这是一个问题),在MSVC上,你有aligned_malloc,你也有Linux的POSIX memalign,然后还有{{1}在ICC,MSVC和GCC,IIRC下工作,这应该是最便携的。

第二个问题是通过对齐来消耗内存,它不会是主要的,但在嵌入式系统上,需要注意的事项。

如果您正在堆栈分配需要对齐的内容(如SIMD类型),您还需要查看_mm_alloc__attribute__((__aligned__(x)))

就指针算法的可移植性而言,您可以使用__declspec(align(x)) / stdint.h中的类型来执行此操作,但标准可能会在pstdint.h和指针(遗憾的是标准不是我的强点:()。

答案 2 :(得分:1)

对齐功能仅在新的C标准C11中处理。它包含关键字_Alignof_Alignas和函数aligned_alloc。这些功能并不是很难用大多数现代编译器来模拟(如其他答案中所示),所以我建议你自己写一些小的宏或包装,你根据__STDC_VERSION__使用它们。< / p>

答案 3 :(得分:1)

主要问题是您只向malloc()和朋友提供内存块的总大小,而不提供有关对象粒度的任何信息。如果您将分配视为对象数组,那么您的大小是基本对象的sizeof,数字n是数组中对象的数量,例如:

p = malloc(sizeof(*p) * n);

如果你只有总大小,那么你不知道s = 4和n = 10,或者s = 2和n = 20,或s = 1和n = 40,因为所有乘以总大小为40个字节。

所以基本的问题是,您是否希望直接替代原始功能,例如:当您在代码库中抛出本机调用时,或者您是否具有包装函数的集中式和DRY模块化。在那里你可以使用提供s和n的函数。

void *my_malloc (size_t s, size_t n)

大多数情况下,当返回的绝对内存地址是s的倍数时,它应该是一个安全的选择,以保证正确的对齐。

或者,在移植实现时,只需查看本机malloc()用于目标平台的对齐方式(例如,16的倍数),并将其用于您自己的实现。

答案 4 :(得分:0)

如果您查看#pragma pack,这可能对您有所帮助,因为它允许您定义结构打包并在大多数编译器上实现。

答案 5 :(得分:0)

C表示malloc返回指向内存的指针,用于任何目的。 C中没有可移植的方法来实现C功能。这导致malloc是一个函数,如果用C语言写不能以便携方式编写。

  

(C99,7.20.3p1)“如果分配成功,则返回的指针被适当地对齐,以便可以将其指定给指向任何类型对象的指针,然后用于访问此类对象或此类对象的数组。分配的空间(直到空间被明确解除分配)。“