将指向局部变量的指针传递给函数:它安全吗?

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 仍然有效。

这就是为什么,通常通常允许将局部变量的地址传递给另一个函数(变量的生命周期没有结束)但是,returning 局部变量的地址(紧接着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 语言字符串拷贝 ( 函数形参使用推荐方法 | 凡是涉及 修改指针指向 的操作一律创建新的 指针变量 执行 | 引入 辅助 局部 指针变量 )

函数返回局部变量

为啥将局部变量推回 Vectorworks

将局部变量从一个函数传递到另一个函数