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

C++ 为什么定义malloc(0)实现的返回值?,c++,c,memory-management,malloc,C++,C,Memory Management,Malloc,ISO/IEC 9899:TC2(即C99标准),§7.20.3规定: 如果请求的空间大小为零,则行为由实现定义: 要么返回空指针,要么行为就好像大小为 非零值,但返回的指针不得用于访问对象 换句话说,malloc(0)可能返回NULL或一个有效指针,我可能不会取消引用 这种行为背后的基本原理是什么? 仅仅定义malloc(0)导致UB不是更容易吗?因为分配0字节实际上可能有意义。例如,当您分配一个项目数未知的数组时。UB将允许程序崩溃,而根据当前行为,您可以安全地分配numberOfItems

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

如果请求的空间大小为零,则行为由实现定义: 要么返回空指针,要么行为就好像大小为 非零值,但返回的指针不得用于访问对象

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

这种行为背后的基本原理是什么?

仅仅定义malloc(0)导致UB不是更容易吗?

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

逻辑如下:如果请求0字节,则返回一个指针。当然,您不能取消对它的引用,因为这将访问第0个字节(您尚未分配)。但是你可以安全地释放内存。因此,不需要将0设为特例

这是关于为什么不将
malloc(0)
定义为UB。关于不严格定义结果的决定(
NULL
vs.指向空格的唯一指针),请参见James的回答。(简而言之:这两种方法各有优缺点。返回唯一非空指针的想法更具说服力,但需要更多的概念性工作,给实现者带来更多负担。)

(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 */
} 
据报道,这种编码风格被广泛使用,但不一定得到委员会的认可

一些实现为零字节的分配请求返回了非空值。
尽管该策略在理论上具有区分“无”和“零”(未分配的指针与指向零长度空间的指针)的优势,但它在理论上具有更引人注目的缺点,即需要零长度对象的概念

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

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

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

使
malloc(0)
产生UB会更糟糕。就目前情况而言,只要在调用
free
时保持一致,就不必关心大小为零时会发生什么


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

我从未想到有人会认为C99应该有更多的行为。@yes123:我不明白你为什么会这么做,但你可以称之为malloc(n)如果n==0,则不必检查。如果malloc(0),我也可以安全地释放指针只返回NULL。是的,无论返回哪一个指针都允许:NULL或non-NULL。使用
realloc
大小为零的指针返回最小大小分配的指针有时可能是有利的,如果具有相同指针的后续非零大小请求能够重用相同的空间(如果仍然可用);如果
realloc
可以为大小为零的请求返回非null,那么允许
malloc
也返回非null也是有意义的。如果我没有弄错的话,如果分配零字节的请求总是导致空指针,那么上述范例仍然可以完美工作,因为realloc(null,n)=malloc(n).对我来说,上述范例没有解释为什么需要有两个可能的malloc(0)返回值。然而,我认为这将是我们能得到的最好的答案,所以我接受它。@Philip:开始的例子是解释为什么结果没有定义。无论返回null还是其他指针都会起作用,但如果结果没有定义就不起作用。我相信下面的解释是分开的从这个例子来看,允许null或其他指针的原因是“一些实现为零字节的分配请求返回了非null值”,但“C89委员会决定……分配函数因此可能为零字节的分配请求返回null指针。”实际上,@R.的回答很好地解释了这一点:C直到有很多实现在某些情况下具有不同的行为时才被标准化,所以C90是某种“折衷”。没有参考文献R…?我同意要求免费的对称性,我认为这使它变得“纯粹”。a+1的一些链接。对不起,我现在不知道任何链接。我只是根据自己的经验知道GNU软件(通过autoconf/gnulib)坚持测试系统
malloc(0)
是否返回非空指针,如果不返回,就对其进行可怕的包装攻击。