ISO / IEC 9899:TC2(即C99标准),§7.20.3规定:
如果请求的空间大小为零,则行为是实现定义的: 返回空指针,或者行为就像大小一样 非零值,但返回的指针不得用于访问对象。
换句话说,malloc(0)可以返回NULL或者我可能不会取消引用的有效指针。
这种行为背后的理由是什么?
并且定义malloc(0)导致UB会不会更容易?
答案 0 :(得分:15)
C99 Rationale(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中的安静更改:依赖于返回非空指针的大小为零的分配请求的程序将表现不同。
答案 1 :(得分:9)
因为分配0个字节实际上可能有意义。例如,当您分配具有未知数量的项目的数组时。 UB会允许程序崩溃,而使用当前行为,您可以安全地分配numberOfItems * itemSize
个字节。
逻辑如下:如果你要求0字节,你会得到一个指针。当然,您不能取消引用它,因为这将访问第0个字节(您尚未分配)。但是你可以安全地释放内存。所以你不需要把0作为一个特例。
这就是为什么不将malloc(0)
定义为UB。关于不严格定义结果的决定(NULL
与空白空间的唯一指针),请参阅James的回答。 (简而言之:两种方法都有其优点和缺点。返回唯一的非空指针的想法更具吸引力,但需要更多的概念性工作,并给实现者带来更多负担。)
答案 2 :(得分:4)
使malloc(0)
导致UB会更糟糕。就目前而言,只要您对调用free
保持一致,就不必关心大小为零时会发生什么。
问题是一些现有的实现为malloc(0)
分配一个指针,一些返回空指针,几乎所有实现都坚持坚持他们的行为,因为编写实现的人写了很多坏,利用其所选行为的非便携式软件(GNU是该领域最严重的违法者)。因此,标准陷入困境,允许这两种行为让他们都满意。