为什么malloc(0)的返回值是实现定义的?

Phi*_*lip 16 c c++ malloc memory-management

ISO/IEC 9899:TC2(即C99标准),§7.20.3规定:

如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象.

换句话说,malloc(0)可以返回NULL或有效指针,我可能不会取消引用.

这种行为背后的理由是什么?
并且定义malloc(0)导致UB不是更容易吗?

Jam*_*lis 15

C99基本原理(PDF链接)讨论了内存管理功能(从C99 7.20.3),并解释说:

在这些函数的定义中处理空指针和零长度分配请求部分是由支持这种范例的愿望指导的:

OBJ * p; // pointer to a variable list of OBJs
    /* initial allocation */
p = (OBJ *) calloc(0, sizeof(OBJ)); 
    /* ... */
    /* reallocations until size settles */
while(1) { 
    p = (OBJ *) realloc((void *)p, c * sizeof(OBJ)); 
      /* change value of c or break out of loop */
} 
Run Code Online (Sandbox Code Playgroud)

据报道,这种编码方式未得到委员会的认可,因此得到广泛使用.

某些实现已为零字节的分配请求返回了非空值.
虽然这种策略具有区分"无"和"零"(未分配指针与指向零长度空间的指针)的理论优势,但它具有更迫切的理论缺点,即需要零长度对象的概念.

由于无法声明此类对象库,因此它们可能存在的唯一方法是通过此类分配请求.

C89委员会决定不接受零长度物体的想法.因此,分配函数可以返回零指针分配请求的空指针.请注意,这种处理方法并不排除上述范例.

C89中的安静更改:依赖于返回非空指针的大小为零的分配请求的程序将表现不同.

  • 如果我没记错的话,如果分配零字节的请求总是导致 NULL 指针,上面的范例仍然可以完美地工作,因为 realloc(NULL, n) == malloc(n)。对我来说,上面的范例并没有解释为什么必须有两个可能的 malloc(0) 返回值。 (2认同)

Vla*_*lad 9

因为分配0个字节实际上可能有意义.例如,当您分配具有未知数量的项目的数组时.UB会允许程序崩溃,而使用当前行为,您可以安全地分配numberOfItems * itemSize字节.

逻辑如下:如果你要求0字节,你会得到一个指针.当然,您不能取消引用它,因为这将访问第0个字节(您尚未分配).但是你可以安全地释放内存.因此,您不需要将0设为特殊情况.

这就是为什么不定义malloc(0)为UB.关于不严格定义结果的决定(NULL与空白空间的唯一指针相比)请参阅James的回答.(简而言之:两种方法都有其优点和缺点.返回唯一的非空指针的想法更具吸引力,但需要更多的概念性工作,并给实现者带来更多负担.)

  • 如果malloc(0)刚刚返回NULL,我也可以安全地释放指针. (3认同)

R..*_*R.. 5

使得malloc(0)在UB结果会更糟。就目前而言,您不必关心大小为零时会发生什么,只要您对调用free.

问题是一些现有的实现为 分配了一个指针malloc(0),一些返回空指针,而且几乎所有的实现都坚持坚持他们的行为,因为编写实现的人写了很多糟糕的、不可移植的软件,这些软件利用了他们选择的行为(GNU 是该领域最严重的罪犯之一)。因此,标准卡住了,允许两种行为让他们都开心。