编译器是否允许回收已释放的指针变量?

15

有人声称

在使用realloc函数释放指针变量后编译器可以自由地将该指针变量用于其他目的,因此您不能保证它具有与之前相同的值

void *p = malloc(42);
uintptr_t address = (uintptr_t)p;
free(p);

// [...] stuff unrelated to p or address

assert((uintptr_t)p == address);

可能会失败。

C11附录J.2如下:

指向由free或realloc函数释放的空间的指针的值被使用(7.22.3)[未定义]

但显然该附录不是规范性的。

附录L.3(规范,但可选)告诉我们,如果

指向由free或realloc函数释放的空间的指针的值被使用(7.22.3)。

结果允许是关键未定义行为。

这证实了该声明,但我想从标准文本中看到一个合适的引用,而不是附录。


1
相关:https://dev59.com/s2Qn5IYBdhLWcg3wLkvL - Oliver Charlesworth
2
话虽如此,这并不意味着编译器会“重用”它。当然,这是未定义行为的一种可能结果。 - Oliver Charlesworth
2
(uintptr_t)p 会导致未定义的行为 - 在释放 p 后,您不允许使用它的值。 (它具有未初始化变量的相同状态) - M.M
@georgem:是的,这显然是未定义行为;因此指针不仅仅是带有糖衣的整数 - 如果将它们按值传递给“神奇”函数,它们可能会失效;就我个人而言,我认为这违反了POLA原则,但事实就是这样... - Christoph
1
“编译器可能会‘重用’它”并不符合逻辑。——如果你理解“可能”一词和基本的情态逻辑,那么就是符合逻辑的。 - Jim Balter
显示剩余2条评论
1个回答

16
当一个对象结束其生命周期时,指向它的所有指针都变得不确定。这适用于块作用域变量和malloc分配的内存。在C11中适用的条款为6.2.4:2。
对象的生命周期是程序执行期间保证为其保留存储空间的部分。对象存在,并保持其在整个生命周期中的最后存储值。如果在生命周期外引用对象,则行为未定义。当指向对象(或刚过去)的指针到达其生命周期的结尾时,指针的值变得不确定。
使用不确定的内存进行任何操作,包括明显无害的比较或算术运算,都是未定义的行为(在C90中;后来的标准使事情变得非常复杂,但编译器继续将使用不确定内存视为未定义行为)。
例如,下面的程序打印出"p"和"q"既不同又相同?各种编译器执行的结果显示在此处
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char *argv[]) {
  char *p, *q;
  uintptr_t pv, qv;
  {
    char a = 3;
    p = &a;
    pv = (uintptr_t)p;
  }
  {
    char b = 4;
    q = &b;
    qv = (uintptr_t)q;
  }
  printf("Roses are red,\nViolets are blue,\n");
  if (p == q)
    printf ("This poem is lame,\nIt doesn't even rhyme.\n");
  else {
    printf("%p is different from %p\n", (void*)p, (void*)q);
    printf("%"PRIxPTR" is not the same as %"PRIxPTR"\n", pv, qv);
  }
}

1
如果可以的话,我会再给您的http://blog.regehr.org/archives/1180点个赞——虽然我不同意所有的建议,但它确实值得深思。 - Christoph
@Christoph 这完全违背了 SO 的精神 :) - Pascal Cuoq
@PascalCuoq:你认为http://en.cppreference.com/w/c/language/analyzability怎么样?如果捕获是可选的,并且更改允许一些目前非法的指针操作,我认为编译器实现起来应该相当容易[如果它们大部分忽略了捕获部分]。 - supercat
@supercat 这很有趣,但是球在编译器实现者的场上。 - Pascal Cuoq
1
这个链接:http://blog.regehr.org/archives/1180,是一个非常明智的想法,我希望这个想法能够在某个时候得到实施。 - Giorgi Moniava
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接