我遇到了以下代码:
int main()
{
char *A=(char *)malloc(20);
char *B=(char *)malloc(10);
char *C=(char *)malloc(10);
printf("\n%d",A);
printf("\t%d",B);
printf("\t%d\n",C);
return 0;
}
//output-- 152928264 152928288 152928304
我想知道malloc()
如何完成分配和填充。查看输出我可以看到起始地址是8的倍数。还有其他规则吗?
答案 0 :(得分:10)
在GNU系统中由malloc或realloc返回的块的地址始终是8的倍数(或64位系统上的16)。
通常,malloc
实现是特定于系统的。所有这些都为自己的簿记(例如分配的块的实际长度)保留了一些内存,以便在您调用free
时能够正确释放该内存。如果需要与特定边界对齐,请使用其他功能,例如posix_memalign
。
答案 1 :(得分:4)
唯一的标准规则是malloc
返回的地址将适当地对齐以存储任何类型的变量。这究竟意味着什么是平台特定的(因为对齐要求因平台而异)。
答案 2 :(得分:0)
对于32位Linux系统:
当malloc()分配内存时,它以8的倍数(8的填充)分配内存,并为记账分配额外的8个字节。
例如:
malloc(10)和malloc(12)将分配24字节内存(填充后为16字节+8 用于簿记的字节。)
malloc()执行填充,因为返回的地址将是8的倍数,因此对任何类型的指针都有效。当我们调用自由函数时,使用簿记8个字节。簿记字节存储已分配内存的长度。
答案 3 :(得分:0)
C标准规定malloc()
的结果必须可转换为任何合法指针类型。所以
... = (DataType *)malloc(...);
无论DataType
是什么类型,都必须是可能的。
如果系统对某些数据类型有内存对齐要求,则malloc()
必须考虑到这一点。而且由于malloc()
无法知道将结果转换为哪种指针类型,因此它必须始终遵循最严格的内存对齐要求。
标准中的原始措辞为:
如果分配成功,则返回的指针将进行适当对齐,以便可以将其分配给具有基本对齐要求的任何类型的对象的指针,然后将其用于在分配的空间中访问此类对象或此类对象的数组(直到明确释放了空间)。
来源: ISO / IEC 9899:201x (又名 ISO C11 )
例如如果系统要求int
对齐4字节,而long
对齐8字节,则malloc()
必须返回8字节对齐的内存,因为它不知道您是否要强制转换结果到int
或long
。
从理论上讲,如果您请求的字节数少于sizeof(long)
,则强制转换为long *
是无效的,因为long
甚至都不适合该内存。有人可能认为在这种情况下,malloc()
可以选择较小的对齐方式,但这不是标准所说的。标准中的对齐要求不取决于分配的大小!
由于许多CPU和许多操作系统确实有对齐要求,因此大多数malloc实现将始终返回对齐的内存,但是遵循的对齐规则是系统特定的。还有一些CPU和系统没有对齐要求,在这种情况下,malloc()
可能还返回未对齐的内存。
如果您依赖特定的对齐方式,则可以使用 ISO C11 标准中定义的aligned_alloc()
,从而可以将存在该C11编译器的所有系统移植到您的系统中,或者可以使用posix_memalign()
,它在IEEE Std 1003.1-2001 (又名 POSIX 2001 )中定义,并且在所有符合POSIX的系统以及尽可能符合POSIX(例如Linux)。
有趣的事实:
尽管事实上macOS上没有数据类型的内存对齐要求超过8,但macOS上的malloc()
始终返回16字节对齐的内存。原因是SSE。某些SSE指令要求16字节对齐,并且通过确保malloc()
始终返回16字节对齐的内存,Apple通常可以在其标准库中使用SSE优化。