【问题标题】:Is a local defined array valid outside its function where it is defined?本地定义的数组在其定义的函数之外是否有效?
【发布时间】:2016-02-18 13:59:02
【问题描述】:

如果我们在SomeFunction 中定义一个数组,它在其范围内是有效的。但它实际上存储在哪里?局部变量通常存储在堆栈上,但我问自己是整个数组存储在堆栈上,还是只是指向数据字段的指针,数据实际存储在其中(比如调用在堆上分配内存的 malloc)。谈论在微控制器中的实现。

所以这个问题也让我想到了另一个问题。如果数据存储在堆中,如果指针将被保存到pdata并在不同的范围(SomeOtherFunction)中访问,这是否是一个有效的操作?数据是否可以在那里使用,或者我如何知道数据是否不再有效?

#define DATAFIELDLEN 127

static uint8_t* pdata;

static void SomeFunction()
{
    uint8_t dataField[DATAFIELDLEN] = {};

    // Write some stuff to the datafield

    pdata = dataField;  // Save pointer to the datafield
}

static void SomeOtherFunction()
{
    // Use datafield here
    for(uint8_t ii=0; ii<DATAFIELDLEN; ii++){
        // Dereference Data here
        someOperation(pdata[ii]);       // <-------- is the data valid here?
    }
}

void main() 
{
    SomeFunction();
    SomeOtherFunction();
}

另一种可能性是将这个文件的全局范围内的数据字段定义为static。然后数据存储在零初始化数据中,在整个文件中有效。但是在我提出的方法中,我想通过不始终保持此数据字段可用来节省 RAM 中的一些空间。或者还有其他有用的做法吗?

【问题讨论】:

  • 您为什么不查找 C11 草案标准,6.2.4 Storage durations of objects
  • "local" 是范围问题,而不是生命周期问题。不要将其与自动变量混淆!

标签: c arrays memory scope lifetime


【解决方案1】:

不,那里的数据无效。你可以让它有点有效,但这真的很危险。让我解释一下。

当您在SomeFunction() 中分配数组时,它会在堆栈上分配。这意味着一旦您从该函数返回,内存将在将来的某个时候被覆盖,因为堆栈被使用。您将取消引用指向您并未真正控制的内存区域的指针。有时您可能会侥幸逃脱,但这绝对是未定义的行为。

另一方面,虽然非常非常不建议,但您可以将该数组标记为static。如果你这样做了,它将不再在堆栈上分配,当它超出范围时你可以继续访问它。请注意,我不建议将此作为一个好的解决方案。

使这个保持有效的正确方法是malloc()它的内存并用pdata指向它。

【讨论】:

  • 即使他会去使用malloc(),但我希望他不要忘记使用free()
  • 当然... 不言而喻。
  • 这种数组在应用程序持续时间内存在的另一种方式是,如果声明后的代码进入无限循环,可能是在阻塞系统调用周围。并不少见,但超出了 C 的范围。
【解决方案2】:

不,dataField 是函数 SomeFunction() 的局部变量。一旦函数执行完毕,dataField 就不存在了。

在函数外部访问dataField 的任何方式(将其保存到全局指针,返回指针然后在调用者中使用它)都会导致无效的内存访问,进而调用undefined behavior

为了详细说明这一点,引用C11 标准,第 §6.2.4 章,对象的存储持续时间,(强调我的

对象的生命周期是程序执行的一部分,在此期间存储是 保证为它保留。一个对象存在,有一个常量地址,33) 并保留 它在其整个生命周期中的最后存储值。34) 如果一个对象在其外部被引用 生命周期,行为未定义。当指针的值变得不确定时 它指向(或刚刚过去)的对象达到其生命周期的终点。

另外,对于自动局部变量,

一个对象,其标识符被声明为没有链接且没有存储类 说明符 static 具有自动存储持续时间,[...] 对于没有可变长度数组类型的此类对象,其生命周期会延长 从进入与其关联的块直到该块的执行结束 任何方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-16
    • 1970-01-01
    • 2018-03-10
    相关资源
    最近更新 更多