【问题标题】:Why is the return value of malloc(0) implementation-defined?为什么 malloc(0) 的返回值是实现定义的?
【发布时间】:2011-07-19 08:37:02
【问题描述】:

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

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

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

这种行为背后的原因是什么?
仅仅定义 malloc(0) 导致 UB 不是更容易吗?

【问题讨论】:

  • 我没想到有人会争论 C99 应该有更多的一件事是未定义的行为。
  • @yes123:我不明白你为什么会这样做,但你可能会调用 malloc(n) 而不检查 n == 0。
  • 另请阅读接受的答案here

标签: c++ c memory-management malloc


【解决方案1】:

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 中的QUIET CHANGE:依赖于大小为零的分配请求返回非空指针的程序将表现不同。

【讨论】:

  • 如果我没记错的话,如果分配零字节的请求总是会导致 NULL 指针,那么上述范例仍然可以完美工作,因为 realloc(NULL, n) == malloc(n) .对我来说,上面的范例并没有解释为什么需要有两个可能的 malloc(0) 返回值。
  • 不过,我认为这将是我们能得到的最佳答案,所以我接受了。
  • @Philip:开头的例子解释了为什么结果不是未定义的。无论返回 null 或其他指针,它都会起作用,但如果结果未定义,它将不起作用。下面的解释是,我认为打算与示例分开,因此允许 null 或其他一些指针的原因是“某些实现已为零字节的分配请求返回非 null 值”但“C89委员会决定……分配函数因此可能会为零字节的分配请求返回一个空指针。”
  • 实际上,@R. 的回答很好地解释了这一点:直到有很多实现在某些情况下具有不同的行为,C 才标准化,所以 C90 是一种“妥协” .
【解决方案2】:

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

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

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

【讨论】:

  • 如果 malloc(0) 返回 NULL,我也可以安全地释放指针。
  • 是的,无论返回哪个指针都允许这样做:NULL 或非NULL。
  • 如果具有相同指针的后续非零大小请求能够重用相同的空间,则让realloc 的大小为零返回一个用于最小大小分配的指针有时可能是有利的(如果仍然可用);如果realloc 可以为大小为零的请求返回非空值,那么对于malloc 也允许这样做是有意义的。
【解决方案3】:

让malloc(0) 导致 UB 会更糟。就目前而言,您不必关心大小为零时会发生什么,只要您始终如一地调用free。

问题是一些现有的实现为malloc(0)分配了一个指针,一些返回空指针,几乎所有人都坚持他们的行为,因为编写实现的同一个人写了很多不好的,非利用他们选择的行为的便携式软件(GNU 是该领域最严重的违规者之一)。因此,标准卡住了,允许这两种行为都让他们都开心。

【讨论】:

  • 没有参考 R..?!我同意要求free 的对称性,我认为这使它“纯粹”。 +1 的一些链接。
  • 对不起,我不知道任何链接。我只是从我自己的经验中知道,GNU 软件(通过 autoconf/gnulib)坚持测试系统 malloc(0) 是否返回一个非空指针,如果没有,它会在它周围进行这种可怕的包装破解。
猜你喜欢
  • 2011-01-09
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 2023-02-02
  • 2017-10-08
  • 1970-01-01
  • 2011-12-07
  • 2015-06-17
相关资源
最近更新 更多