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

Chr*_*oph 14 c free pointers standards-compliance compiler-optimization

有人声称

编译器可以自由地将指针变量重用于其他目的之后 realloc 被释放,所以你不能保证它具有与之前相同的价值

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

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

assert((uintptr_t)p == address);
Run Code Online (Sandbox Code Playgroud)

可能会失败.

C11附件J.2读

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

但附件当然不是规范性的.

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

使用指向通过调用free或realloc函数解除分配的空间的指针的值(7.22.3).

结果被允许是关键的未定义行为.

这证实了这一说法,但我希望从标准本身而不是附件中看到适当的引用.

Pas*_*uoq 16

当一个对象到达其生命周期的末尾时,所有指向它的指针都变得不确定.这适用于块范围变量和malloced内存.适用的条款在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);
  }
}
Run Code Online (Sandbox Code Playgroud)