本地定义的数组是否在其定义的函数之外有效?

时间:2016-02-18 13:59:02

标签: c arrays memory scope lifetime

如果我们在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中的一些空间。还是有其他有用的做法吗?

2 个答案:

答案 0 :(得分:1)

不,dataField是函数SomeFunction()的本地。一旦函数完成执行,就不存在dataField

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

详细说明一下,引用C11标准,章节§6.2.4,对象的存储持续时间,(强调我的

  

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

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

  

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

答案 1 :(得分:1)

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

SomeFunction()中分配数组时,它会在堆栈上分配。这意味着一旦从该函数返回,将来在使用堆栈时将覆盖内存。您将取消引用指向您实际上无法控制的内存区域的指针。你有时可能会侥幸逃脱,但这肯定是未定义的行为。

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

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