rav*_*ron 14 c pointers lifetime
假设我有一个声明和初始化两个局部变量的函数 - 默认情况下它具有存储持续时间auto.然后,该函数调用第二个函数,它传递这两个局部变量的地址.第二个功能可以安全地使用这些指针吗?
一个简单的程序化示例,以补充该描述:
#include <stdio.h>
int adder(int *a, int *b)
{
return *a + *b;
}
int main()
{
auto int a = 5; // `auto' is redundant; included for clarity
auto int b = 3;
// adder() gets the addresses of two auto variables! is this an issue?
int result = adder(&a, &b);
printf("5 + 3 = %d\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序按预期工作,打印5 + 3 = 8.
通常,当我对C有疑问时,我会转向标准,这也不例外.具体来说,我检查了ISO/IEC 9899,§6.2.4.它在那里说:
4声明标识符且没有链接且没有存储类说明符的对象
static具有自动存储持续时间.5对于没有可变长度数组类型的对象,其生命周期从entry进入与其关联的块,直到该块的执行以任何方式结束.(输入一个封闭的块或调用一个函数暂停,但不会结束,执行当前块.)如果以递归方式输入块,则每次都会创建一个新的对象实例.对象的初始值是不确定的.如果为对象指定了初始化,则每次在执行块时达到声明时都会执行初始化; 否则,每次达到声明时,该值将变为不确定.
读到这篇文章,我提出以下几点:
变量a和b存储持续时间auto,我已使用auto关键字明确表示.
adder()在上面的部分引用中,调用该函数对应于第5节中的括号.也就是说,进入adder()函数"暂停但不结束"当前块的执行(即main()).
由于该main()块不是"以任何方式结束",a因此b可以保证存储.因此,使用该地址访问它们&a和&b,甚至里面adder(),应该是安全的.
那么我的问题是:我对此是否正确?或者我只是"幸运",并访问记忆位置,偶然,没有被覆盖?
PS我无法通过Google或SO的搜索找到这个问题的确切答案.如果可以,请将此标记为重复,我将删除它.
是的,它是安全的,基本上你的假设是正确的.自动对象的生命周期来自声明它的块中的条目,直到块终止.
(C99,6.2.4p5)"对于这样的对象[...],它的生命周期从进入与其相关联的块延伸,直到该块的执行以任何方式结束.
您的推理对于您的特定函数调用链是正确的,并且您已阅读并引用了标准的相关部分.这是对局部变量指针的完美有效使用.
如果函数将指针值存储在寿命比其自己的调用长的结构中,则必须要小心.考虑两个函数foo(),和bar():
int *g_ptr;
void bar (int *p) {
g_ptr = p;
}
void foo () {
int x = 10;
bar(&x);
}
int main () {
foo ();
/* ...do something with g_ptr? */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,变量xs的生命周期以foo()返回结束.然而,指针x已经存储在g_ptr由bar().在这种情况下,它是一个错误foo()的指针传递给它的本地变量x到bar().
这意味着,为了知道将指向局部变量的指针传递给函数是否有效,您必须知道该函数将对它执行什么操作.