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

Passing pointer to local variable to function: is it safe?

例如:

void func1(){
    int i = 123;
    func2(&i);
}
void func2(int *a){
    *a = 456;
}

func1调用func2时,指向局部变量的指针被传递给func2——指针指向堆栈。这对 C 语言的规则安全吗?

谢谢。

是的,传递一个指向局部变量的指针是安全的,但你不能return从函数中传递一个指向自动局部变量的指针。

是的,您的代码是安全的。

只要对象的生命周期没有结束,像你这样传递局部变量是安全的。

i 的作用域是 func1,它比对 func2 的调用更有效。所以绝对安全。

Is this safe for the rules of C?

你所做的是安全的,因为局部变量仍然有效并且在范围内。在其范围之外访问本地变量是未定义的行为,但这完全没问题

在您的情况下,您可以安全地使用 &i 直到 i 有效。

现在,我们可以看到 i 的生命周期到 func1() 结束。因为,func2()是从func1()调用的,而func1()还没有执行完,所以,i仍然有效。

这就是为什么,通常将局部变量的地址传递给另一个函数是 通常 允许的(变量的生命周期尚未结束)但是,returning 地址局部变量的(在 return 之后,函数的局部变量不复存在)是 不允许的

TL;DR :您可以安全地使用 &i 作为 func2() 的参数,如此处所示。

如之前大多数答案所述,在您的特殊情况下将指针传递给 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;
}

这样的话,DataBuff中的数据早就没有了,用ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr中的指针将数据存入EEPROM

要修复此代码,至少需要声明 static UINT8 DataBuff[25]; 此外,还应考虑声明 static valueObj_t NVMemObj,因为我们不知道被调用的函数正在做什么指针。

简而言之: TL;DR

尽管在 C 语言中是合法的,但我认为在函数调用中将指针传递给自动变量是有害的。您永远不知道(通常您也不想知道)被调用函数对传递的值究竟做了什么。当被调用的函数建立别名时,你就有大麻烦了。

只是我的 2 美分。