如果`malloc(0)`返回一个非空指针,我可以把它传递给`free`吗?

我一直在阅读关于在请求一个零大小的块时malloc行为的讨论。

我明白, malloc(0)的行为是实现定义的,它应该返回一个空指针, 或者一个非空指针,但我不应该访问。 (这是有道理的,因为不能保证它指向任何可用的内存。)

但是,如果得到这样一个不可访问的非空指针,我可以通过它以通常的方式来free它? 或者是非法的,因为我从malloc(0)得到的指针可能不指向一个实际分配的内存块?

具体来说,下面的代码是否有明确的行为:

 #include <stdio.h> #include <stdlib.h> int main() { int* x = (int*) malloc(0); if (x == NULL) { printf("Got NULL\n"); return 0; } else { printf("Got nonnull %p\n", x); } free(x); // is calling `free` here okay? } 

C99标准(实际上是WG14 / N1124委员会草案 – 2005年5月6日,ISO / IEC 9899:TC2)对malloc()

指针返回指向分配空间的开始(最低字节地址)。 如果空间不能分配,则返回空指针。 如果请求空间的大小为零,则行为是实现定义的:或者返回空指针,或者行为就好像大小是非零值一样,除了返回的指针不能用于访问对象

和关于free()

否则,如果参数与先前由calloc,malloc或realloc函数返回的指针不匹配,或者如果通过调用free或realloc释放空间,则行为是未定义的。

IEEE Std 1003.1-2008(POSIX),2016版说关于free()

free()函数将导致ptr指向的空间被释放; 即可供进一步分配。 如果ptr是空指针,则不会发生任何操作。 否则,如果参数不匹配POSIX.1-2008中由malloc()分配内存的函数返回的指针,或者通过调用free()或realloc()释放空间,行为是不确定的。

所以,无论*alloc()返回什么,都可以传递给free()

至于malloc()的当前实现:

FreeBSD使用贡献的jemalloc

 void * je_malloc(size_t size) { void *ret; size_t usize JEMALLOC_CC_SILENCE_INIT(0); if (size == 0) size = 1; [...] 

而苹果的libmalloc呢

 void * szone_memalign(szone_t *szone, size_t alignment, size_t size) { if (size == 0) { size = 1; // Ensures we'll return an aligned free()-able pointer [...] 

GLIBC也改变了要求的大小; 它正在使用一个调用这个macros的请求大小(以字节为单位)作为参数来resize到一个特定的边界或简单的最小分配大小:

 #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) 

是的,事实上,你必须这样做,以避免可能的内存泄漏。

malloc系统通常会在指针之前的空间中返回一个隐藏的控制块,其中包含分配大小等信息。 如果分配大小为零,则该块仍然存在并占用内存,如果malloc返回非null。