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

时间:2014-09-27 10:46:53

标签: c pointers free compiler-optimization standards-compliance

据称已经声称

  

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 个答案:

答案 0 :(得分:16)

当一个对象到达其生命周期的末尾时,指向它的所有指针都变为 indeterminate 。这适用于块范围变量和malloced内存。适用的条款在C11,6.2.4:2中。

  

对象的生命周期是程序执行的一部分,在此期间保证为其保留存储。存在一个对象,具有一个常量地址,并在其整个生命周期内保留其最后存储的值。如果在其生命周期之外引用对象,则行为未定义。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。

对任何事物使用不确定的内存,包括显然无害的比较或算术,都是未定义的行为(在C90中;后来的标准使事情变得非常复杂,但编译器继续将不确定内存的使用视为未定义的行为)。

例如,pq的以下程序打印如何不同且相同?使用各种编译器执行的结果显示为here

#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);
  }
}