将指向局部变量的指针传递给函数:它安全吗?
Posted
技术标签:
【中文标题】将指向局部变量的指针传递给函数:它安全吗?【英文标题】:Passing pointer to local variable to function: is it safe? 【发布时间】:2015-04-17 21:15:32 【问题描述】:例如:
void func1()
int i = 123;
func2(&i);
void func2(int *a)
*a = 456;
当func1
调用func2
时,将一个指向局部变量的指针传递给func2
——该指针指向堆栈。这对 C 的规则安全吗?
谢谢。
【问题讨论】:
在变量销毁后使用指向变量的指针是不安全的。你不是在这里做的。 Safe to pass pointer to auto variable to function?的可能重复 【参考方案1】:是的,将指针传递给局部变量是安全的,但不能从函数返回指向自动局部变量的指针。
【讨论】:
【参考方案2】:是的,您的代码是安全的。
只要对象的生命周期没有结束,就可以像你一样传递局部变量。
【讨论】:
【参考方案3】:i
的范围是func1
,它比对func2
的调用要长。所以它是绝对安全的。
【讨论】:
【参考方案4】:这对于 C 的规则是否安全?
您所做的是安全的,因为局部变量仍然有效并且在范围内。在其范围之外访问本地变量是未定义的行为,但这完全没问题
【讨论】:
【参考方案5】:在您的情况下,您可以安全地使用&i
,直到i
有效。
现在,我们可以看到i
的生命周期直到func1()
结束。由于 func2()
正在从 func1()
调用,而 func1()
尚未完成执行,因此,i
仍然有效。
这就是为什么,通常通常允许将局部变量的地址传递给另一个函数(变量的生命周期没有结束)但是,return
ing 局部变量的地址(紧接着return
,函数的局部变量不复存在)是不允许。
TL;DR :您可以安全地使用&i
作为func2()
的参数,如下所示。
【讨论】:
scope 适用于标识符(不是变量),这意味着该标识符在哪里可见,因此i
不在func2
的范围内。也许您正在寻找终身。【参考方案6】:
正如之前大多数答案所述,在您的特殊情况下,将指针传递给func2()
是完全安全的。
然而,在现实世界的软件中,我认为这是有害的,因为您无法控制 func2()
对您的变量所做的事情。 func2()
可以为其参数创建一个别名,以便在以后的时间点异步使用它。并且那个时候局部变量int i
在以后使用这个别名的时候可能就没了。
所以从我的角度来看,将指针传递给本地(自动)变量是非常危险的,应该避免。
如果您将func1()
中的变量声明为static int i;
,则可以这样做
在这种情况下,可以确保i
的内存不会被回收和覆盖。但是,您需要设置一些互斥锁,以便在并发环境中访问此内存。
为了说明这个问题,这里是我昨天在我的客户做软件测试时偶然发现的一些代码。是的,它崩溃了......
void func1()
// Data structure for NVMemory calls
valueObj_t NVMemObj;
// a data buffer for eeprom write
UINT8 DataBuff[25];
// [..]
/* Assign the data pointer to NV Memory object */
NVMemObj.record = &DataBuff[0];
// [..]
// Write parameter to EEPROM.
(void)SetObject_ASync(para1, para2, para3, &NVMemObj);
return;
void SetObject_ASync(para1, para2, para3, valueObj_t *MemoryRef)
//[..]
ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr = MemoryRef->record;
//[..]
return;
在这种情况下,当ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr
中的指针用于将数据存储到EEPROM时,DataBuff
中的数据早已不复存在。
要修复此代码,至少需要声明static UINT8 DataBuff[25];
。此外,还应考虑声明static valueObj_t NVMemObj
,因为我们不知道被调用的函数对该指针做了什么。
简单地说: TL;DR
尽管在 C 语言中是合法的,但我认为在函数调用中传递指向自动变量的指针是有害的。您永远不知道(通常您也不想知道)被调用的函数对传递的值究竟做了什么。当被调用的函数建立别名时,你就麻烦了。
只要我的 2 美分。
【讨论】:
“func2() 可以为其参数创建一个别名,以便在以后的时间点异步使用它”。然而,对于传递给函数的 malloced 内存也是如此……它可能会为其创建一个别名,在调用者稍后释放内存后尝试访问该别名。这里的重点不是调用者做错了什么,而是 被调用函数 保持对它自己的 args 的引用(在哪里?在全局中?)它在 以后的调用中重复使用>。还要考虑这是一个更安全的起点,因为它们不需要被释放。 TLDR;自动变量=好。保持指向其 args=bad 的指针的函数。 @aaa90210 但是这个例子没有使用 malloc 的内存。它使用static
缓冲区,保证在进程的整个生命周期中都存在。所以我同意,malloc 或 C++ new
是危险的。但使用互斥锁的静态不是。以上是关于将指向局部变量的指针传递给函数:它安全吗?的主要内容,如果未能解决你的问题,请参考以下文章
C 语言字符串拷贝 ( 函数形参使用推荐方法 | 凡是涉及 修改指针指向 的操作一律创建新的 指针变量 执行 | 引入 辅助 局部 指针变量 )