通过从本地 C 样式数组返回指针来获取悬空指针
Posted
技术标签:
【中文标题】通过从本地 C 样式数组返回指针来获取悬空指针【英文标题】:Getting a dangling pointer by returning a pointer from a local C-style array 【发布时间】:2018-09-13 01:27:31 【问题描述】:我对下面的代码有点困惑:
#include <iostream>
const char* f()
const char* arr[]="test";
return arr[0];
int main()
auto x = f();
std::cout << x;
在我看来,这段代码应该是 UB(未定义的行为)。我们返回一个指向本地范围内的 C 样式数组元素的指针。事情应该出错了。但是,我测试过的编译器都没有抱怨(我在 g++ 和 clang 上都使用了-Wall -Wextra -pedantic
)。 valgrind
也不抱怨。
上面的代码是有效的还是像人们想象的那样是 UB?
PS:运行它似乎会产生“正确”的结果,即显示“测试”,但这并不表示正确性。
【问题讨论】:
FWIW 它在实践中“工作”的原因是常量字符串“test”被存储在可执行文件的静态数据区域中,因此即使在函数返回后字符串仍然有效。 (当然,语言规范是否保证它可以工作是另一个问题) 问这些问题没有坏处,而且这个问题写得很好。 +1。 @JesperJuhl 我知道 UB 是什么,以及月球可能因此而爆炸的事实。我在问代码是否真的是UB。看起来不是。看起来很多人认为代码是 UB……所以我认为这个问题很有用。 @Bathsheba 看来我们还在学习 :) 确实代码 不是 UB。 @vsoftco:没想到是这样,但需要像 Barry 这样的专家来指出原因。 【参考方案1】:不,这不是 UB。
这个:
const char* f()
const char* arr[]="test";
return arr[0];
可以改写成等价的:
const char* f()
const char* arr0 = "test";
return arr0;
所以我们只是返回一个本地指针,指向一个字符串文字。字符串文字有static storage duration,没有任何悬垂。功能真的是一样的:
const char* f()
return "test";
如果你做了类似这个的事情:
const char* f()
const char arr[] = "test"; // local array of char, not array of char const*
return arr;
现在 是 UB - 我们正在返回一个悬空指针。
【讨论】:
"字符串字面量具有静态存储持续时间" - 我知道所有的编译器都这样做;但在标准中,字符串文字必须具有静态持续时间吗? @UKMonkey 是的,添加了参考。 不要迂腐,但这并不是真正的“等效”。从功能上讲,在这种情况下,当然,但数组就是数组。 ;) @LightnessRacesinOrbit,在这两种情况下,都有一个指向const char
的本地指针,在这两种情况下,本地指针都被初始化为指向一个文字字符串,并且在这两种情况下都返回了它的值。唯一的区别是,在原始示例中,本地指针是单元素数组的成员,而在替代版本中,它是标量。那么,如果在某种意义上它们不是“等价的”呢?这里重要的不是局部变量的确切类型。重要的是字符串文字在函数返回后是否仍然有效。
C 还保证字符串文字具有静态存储持续时间,请参阅port70.net/~nsz/c/c11/n1570.html#6.4.5p6。【参考方案2】:
数组arr
具有本地存储持续时间,并将在范围结束时消失。然而,字符串文字"test"
是指向静态存储位置的指针。在返回之前将此指针临时存储在本地数组arr
中不会改变这一点。它始终是一个静态存储位置。
请注意,如果函数要返回 C++ 样式字符串类型而不是 C 样式 const char *
,则根据 C++ 临时规则,额外的转换/簿记可能会使您的值在生命周期内受到限制。
【讨论】:
以上是关于通过从本地 C 样式数组返回指针来获取悬空指针的主要内容,如果未能解决你的问题,请参考以下文章