说我们有:
char *a = malloc(sizeof(char*));
char *b = realloc(a,sizeof(char*));
我们能否安全地说b
不与a
别名? realloc
参考页面说明了这一点
原始指针ptr无效,对它的任何访问都是未定义的行为(即使重新分配就位)。
那么我可以将b
标记为不混淆a
,因为我们不能合法访问a
了吗?然而,这可能导致可疑的优化,其中下面的分支将被消除:
if (a == b)
something..
根据我的理解,a == b
本身的比较将是UB,这是技术上正确的优化吗?
解放后,a
的值是不确定的。
n1570-§6.2.3(p2):
[...]如果在其生命周期之外引用对象,则行为未定义。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。
如果此不确定值成为陷阱表示,则比较a == b
将导致未定义的行为。
请注意,当指针传递给free
时,指针指向的对象的生命周期到达其结尾。
进一步阅读: 1. Why isn't a pointer null after calling free? 2. A dangling pointer is indeterminate。
根据我的理解,
a == b
本身的比较将是UB ..
嗯,是。
关于“为什么”部分,如haccks's answer中提到的,在指针为free()
d之后,它指向的对象到达其生命周期的末尾,从而使指针值不确定。因此,指针本身的任何进一步使用(读取)都将是未指定的行为,并且任何尝试使用它指向的地址都会调用undefined behavior。
因此,从技术上讲,您期望的优化是正确的,并且必须使代码表现出已定义的行为,因为代码开始时是不正确的。不要指望编译器纠正你的代码,它可能不会。
那说,关于
我们可以安全地说“b”不是别名“a”吗?
我不清楚你在这里使用别名的理由,但是可以肯定的是,官方的措辞,来自C11
,章节§7.22.3.5,
P2:
realloc
函数释放ptr
指向的旧对象,并返回指向由size
指定大小的新对象的指针。新对象的内容应与解除分配之前的旧对象的内容相同,直到新旧大小中的较小者为止。 [...]
P3
[...]如果
ptr
是空指针,则realloc
函数的行为类似于指定malloc
的size
函数。否则,如果ptr
与先前由内存管理函数返回的指针不匹配,或者如果通过调用free
或realloc
函数释放了空间,则行为未定义。如果无法分配新对象的内存,则不会释放旧对象,并且其值不会更改。
而且,P4:
realloc
函数返回指向新对象的指针(可能与指向旧对象的指针具有相同的值),如果无法分配新对象,则返回空指针。