如果我们在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中的一些空间。还是有其他有用的做法吗?
答案 0 :(得分:1)
不,dataField
是函数SomeFunction()
的本地。一旦函数完成执行,就不存在dataField
。
访问函数外部的dataField
(将其保存到全局指针,返回指针然后在调用者中使用它)的任何方法都将导致无效的内存访问,而后者又会调用undefined behavior。
详细说明一下,引用C11
标准,章节§6.2.4,对象的存储持续时间,(强调我的)
对象的生命周期是存储期间程序执行的一部分 保证为它保留。存在一个对象,具有恒定的地址,33)并保留 它在整个生命周期中的最后存储值.34)如果一个对象被引用到它的外面 一生,行为是不确定的。当指针变为不确定时,指针的值变得不确定 它指向(或刚刚过去)的对象到达其生命周期的末尾。
另外,对于自动局部变量,
声明标识符的对象,没有链接且没有存储类 说明符
static
具有自动存储持续时间,[...]对于没有可变长度数组类型的对象,其生命周期延长 从进入与之关联的块直到该块的执行结束 无论如何。
答案 1 :(得分:1)
不,那里的数据无效。你可以使它有效,但它真的很危险。让我解释一下。
在SomeFunction()
中分配数组时,它会在堆栈上分配。这意味着一旦从该函数返回,将来在使用堆栈时将覆盖内存。您将取消引用指向您实际上无法控制的内存区域的指针。你有时可能会侥幸逃脱,但这肯定是未定义的行为。
另一方面,虽然确实没有建议,但您可以将该数组标记为static
。如果您这样做,它将不再在堆栈上分配,并且当它超出范围时您可以继续访问它。请注意,我不建议将此作为一个好的解决方案。
使此保持有效的正确方法是malloc()
内存,并使用pdata
指向它。