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

时间:2015-02-17 07:48:37

标签: c pointers stack

例如:

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

func1调用func2时,指向局部变量的指针传递给func2 - 指针指向堆栈。这对C的规则是否安全?

感谢。

6 个答案:

答案 0 :(得分:17)

i的范围是func1,它比func2的呼叫更长。所以这是非常安全的。

答案 1 :(得分:4)

如前面的大多数答案中所述,在您的特殊情况下将指针传递给func2()是完全安全的。

在现实世界的软件中,我认为这有害,因为您无法控制func2()对您的变量做什么。 func2()可以为其参数创建别名,以便在以后的某个时间异步使用它。那时,当稍后使用此别名时,局部变量int i可能会消失。

因此,从我的观点来看,将指针传递给本地(自动)变量是非常危险的,应该避免。

如果您将func1()中的变量声明为static int i;

,则可以这样做

在这种情况下,确保i的内存不会被回收和覆盖。但是,您需要设置一些Mutex锁定,以便在并发环境中对此内存进行访问控制。

为了说明这个问题,这里有一些代码我昨天偶然发现在我的客户进行软件测试时。是的,它崩溃了......

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中的指针用于将数据存储到EEPROM时,ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr中的数据早已消失。

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

简要说一下: 的 TL; DR

即使它在C语言中是合法的,我认为在函数调用中传递指向自动变量的指针是有害的。你永远不会知道(并且通常你不想知道)被调用的函数对传递的值的作用。当被调用的函数建立别名时,你会遇到大麻烦。

只需2美分。

答案 2 :(得分:2)

是的,将指针传递给局部变量是安全的,但是你不能从函数返回指向自动局部变量的指针。

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

  

这对C的规则是否安全?

您正在做的事情是安全的,因为局部变量仍然有效且在范围内。访问其范围之外的本地变量是未定义的behvaior但这是完全没法的

答案 5 :(得分:1)

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

现在,我们可以看到i的有效期一直持续到func1()。因为,func2()正在调用func1()func1()尚未完成执行,因此,i仍然有效。

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

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