我们可以安全地说,realloc 的结果不会与原始指针重叠吗?

4

假设我们有:

char *a = malloc(sizeof(char*));    
char *b = realloc(a,sizeof(char*));

我们能否安全地说ba没有别名关系? 参考页面realloc说:
“原始指针ptr无效,任何访问都是未定义的行为(即使重新分配是就地进行的)。”
因此,我们是否可以将b标记为不与a有别名关系,因为我们不能再合法地访问a了? 然而,这可能会导致一个可疑的优化,下面的分支会被消除:
if (a == b)
  something..

基于我的理解,a == b的比较本身可能是未定义行为(UB),那么这个优化是否在技术上正确呢?

请提供参考链接。 - Ed Heal
1
是的,realloc 可能返回一个不同的地址。当这种情况发生时,旧地址会被 realloc 释放并可以安全地忽略它。但是,如果 realloc 失败,则会返回 NULL ,旧地址仍然有效。 - Pablo
但是 realloc 也可以返回相同的地址(并且仍然增加内存区域...) - Basile Starynkevitch
如果realloc失败了,那么最好保留旧地址(在您的情况下是a),否则您将无法恢复它。所以永远不要执行"a = realloc(a, newSize);"。 - SoronelHaetir
@Pablo 我最初已经给这个问题打了编译器构建的标签,但是一个mod删除了那个标签。我是从编译器优化的角度来看别名wiki-link。是的,我明白为什么我永远不应该做a = realloc(a,..)。谢谢! - MIA
显示剩余5条评论
2个回答

3

释放后,a的值是不确定的。

n1570-§6.2.3 (p2):

[...] 如果在其生命周期之外引用对象,则行为未定义。当指向对象(或刚刚过去)的指针到达其生命周期的末尾时,指针的值变得不确定。

如果该不确定值成为陷阱表示,则比较a == b将导致未定义的行为。

请注意,通过指针传递给free时,所指向的对象的生命周期已经结束。

进一步阅读:
1. 调用free后为什么指针不为空?
2. 悬空指针是不确定的


2
根据我的理解,a == b的比较本身就是未定义行为。
关于“为什么”,如haccks's answer中所述,在指针被free()释放后,它指向的对象达到了生命周期的尽头,从而使得指针值变得不确定。因此,任何进一步使用(读取)指针本身都可能是未指定的行为,而任何试图使用其指向的地址的尝试都会引发未定义行为
因此,从技术上讲,您期望的优化是正确的,并且必须使代码表现出定义良好的行为,因为代码本身就是错误的。不要指望编译器来“纠正”您的代码,它可能不会这样做。
话虽如此,关于“我们可以安全地说'b'与'a'没有别名吗?”
我不太清楚你在这里使用“alias”的原因,但为了确保准确性,从C11第7.22.3.5节中官方措辞如下:
P2:

realloc函数释放由ptr指向的旧对象,并返回一个大小由size指定的新对象的指针。新对象的内容应与释放之前的旧对象相同,最多到新旧大小的较小者。[...]

P3:
如果ptr是空指针,则realloc函数对于指定的size表现得像malloc函数一样。否则,如果ptr与先前由内存管理函数返回的指针不匹配,或者该空间已被调用freerealloc函数释放,则其行为未定义。如果无法为新对象分配内存,则旧对象不会被释放,其值也不会改变。

另外,在P4中提到,realloc函数返回一个指向新对象的指针(可能与旧对象的指针相同),如果无法分配新对象,则返回空指针。


a 被释放后,这里的比较如何有效? - haccks
@PascalCuoq 是的,经过 haccks 的回答,我现在清楚地看到了。它所指向的那个对象不再存在,因此指针是不确定的。我会相应地更新并感谢您的评论。 - Sourav Ghosh
1
@PascalCuoq;哥们!我一直在寻找这篇文章来支持我的回答,因为我记得你曾经在某个地方提到过这篇文章。非常感谢。 - haccks
@haccks 现在我们俩都得收藏它 :) - Sourav Ghosh

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