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

时间:2022-09-10 23:27:29

ISO/IEC 9899:TC2 (i.e. the C99 standard), §7.20.3 states:

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

If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

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

In other words, malloc(0) may either return NULL or a valid pointer which I may not dereference.

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

What is the rationale behind this behavior?
And wouldn't it be easier to just define that malloc(0) leads to UB?

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

3 个解决方案

#1


15  

The C99 Rationale (PDF link) discusses the memory management functions (from C99 7.20.3) and explains:

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

The treatment of null pointers and zero-length allocation requests in the definition of these functions was in part guided by a desire to support this paradigm:

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

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 */
} 

This coding style, not necessarily endorsed by the Committee, is reported to be in widespread use.

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

Some implementations have returned non-null values for allocation requests of zero bytes.
Although this strategy has the theoretical advantage of distinguishing between "nothing" and "zero" (an unallocated pointer vs. a pointer to zero-length space), it has the more compelling theoretical disadvantage of requiring the concept of a zero-length object.

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

Since such objects Library cannot be declared, the only way they could come into existence would be through such allocation requests.

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

The C89 Committee decided not to accept the idea of zero-length objects. The allocation functions may therefore return a null pointer for an allocation request of zero bytes. Note that this treatment does not preclude the paradigm outlined above.

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

QUIET CHANGE IN C89: A program which relies on size-zero allocation requests returning a non-null pointer will behave differently.

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

#2


9  

Because allocating 0 bytes may actually have sense. For example, when you are allocating an array with unknown number of items. UB would allow the program crash, whereas with the current behaviour you can safely allocate numberOfItems * itemSize bytes.

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

The logic is following: if you ask for 0 bytes, you get a pointer back. Of course, you must not dereference it, as this would have accessed 0-th byte (which you haven't allocated). But you can safely free the memory afterwards. So you don't need to make 0 a special case.

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

This was about why not define malloc(0) as UB. About the decision not to define the result strictly (NULL vs. unique pointer to empty space) see James' answer. (In short: both approaches have their advantages and disadvantages. The idea of returning a unique non-null pointer is more compelling, but requires more conceptual work and puts more burden on implementors.)

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

#3


4  

Making malloc(0) result in UB would be much worse. As it stands, you don't have to care what happens when the size is zero, as long as you're consistent about calling free.

使malloc(0)导致UB会更糟糕。就目前而言,你不必关心当大小为零时会发生什么,只要你对*呼叫保持一致。

The problem is that some existing implementations allocate a pointer for malloc(0), some return null pointers, and almost all of them are adamant about sticking with their behavior because the same people who wrote the implementations wrote lots of bad, non-portable software that makes use of their chosen behavior (GNU being among the worst offenders in this area). Thus the standard got stuck allowing both behaviors to keep them all happy.

问题是一些现有的实现为malloc(0)分配一个指针,一些返回空指针,并且几乎所有实现都坚持坚持他们的行为,因为编写实现的人写了很多坏的,不可移植的软件利用他们选择的行为(GNU是这个领域最严重的罪犯)。因此,标准陷入困境,允许这两种行为让他们都满意。

#1


15  

The C99 Rationale (PDF link) discusses the memory management functions (from C99 7.20.3) and explains:

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

The treatment of null pointers and zero-length allocation requests in the definition of these functions was in part guided by a desire to support this paradigm:

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

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 */
} 

This coding style, not necessarily endorsed by the Committee, is reported to be in widespread use.

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

Some implementations have returned non-null values for allocation requests of zero bytes.
Although this strategy has the theoretical advantage of distinguishing between "nothing" and "zero" (an unallocated pointer vs. a pointer to zero-length space), it has the more compelling theoretical disadvantage of requiring the concept of a zero-length object.

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

Since such objects Library cannot be declared, the only way they could come into existence would be through such allocation requests.

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

The C89 Committee decided not to accept the idea of zero-length objects. The allocation functions may therefore return a null pointer for an allocation request of zero bytes. Note that this treatment does not preclude the paradigm outlined above.

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

QUIET CHANGE IN C89: A program which relies on size-zero allocation requests returning a non-null pointer will behave differently.

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

#2


9  

Because allocating 0 bytes may actually have sense. For example, when you are allocating an array with unknown number of items. UB would allow the program crash, whereas with the current behaviour you can safely allocate numberOfItems * itemSize bytes.

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

The logic is following: if you ask for 0 bytes, you get a pointer back. Of course, you must not dereference it, as this would have accessed 0-th byte (which you haven't allocated). But you can safely free the memory afterwards. So you don't need to make 0 a special case.

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

This was about why not define malloc(0) as UB. About the decision not to define the result strictly (NULL vs. unique pointer to empty space) see James' answer. (In short: both approaches have their advantages and disadvantages. The idea of returning a unique non-null pointer is more compelling, but requires more conceptual work and puts more burden on implementors.)

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

#3


4  

Making malloc(0) result in UB would be much worse. As it stands, you don't have to care what happens when the size is zero, as long as you're consistent about calling free.

使malloc(0)导致UB会更糟糕。就目前而言,你不必关心当大小为零时会发生什么,只要你对*呼叫保持一致。

The problem is that some existing implementations allocate a pointer for malloc(0), some return null pointers, and almost all of them are adamant about sticking with their behavior because the same people who wrote the implementations wrote lots of bad, non-portable software that makes use of their chosen behavior (GNU being among the worst offenders in this area). Thus the standard got stuck allowing both behaviors to keep them all happy.

问题是一些现有的实现为malloc(0)分配一个指针,一些返回空指针,并且几乎所有实现都坚持坚持他们的行为,因为编写实现的人写了很多坏的,不可移植的软件利用他们选择的行为(GNU是这个领域最严重的罪犯)。因此,标准陷入困境,允许这两种行为让他们都满意。