【问题标题】: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 的规则安全吗?

谢谢。

【问题讨论】:

标签: c pointers stack


【解决方案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 是危险的。但使用互斥锁的静态不是。
          猜你喜欢
          • 2020-08-08
          • 2013-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-19
          • 1970-01-01
          相关资源
          最近更新 更多