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

有人声称

编译器可以自由地将指针变量重用于其他目的之后 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)。

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

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

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

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

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

作为一个例子, pq的以下程序打印如何不同和相同? 这里显示了使用各种编译器执行的结果。

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