将指向局部变量的指针传递给函数:安全吗?
Passing pointer to local variable to function: is it safe?
例如:
void func1(){
int i = 123;
func2(&i);
}
void func2(int *a){
*a = 456;
}
当func1
调用func2
时,指向局部变量的指针被传递给func2
——指针指向堆栈。这对 C 语言的规则安全吗?
谢谢。
是的,传递一个指向局部变量的指针是安全的,但你不能return从函数中传递一个指向自动局部变量的指针。
是的,您的代码是安全的。
只要对象的生命周期没有结束,像你这样传递局部变量是安全的。
i
的作用域是 func1
,它比对 func2
的调用更有效。所以绝对安全。
Is this safe for the rules of C?
你所做的是安全的,因为局部变量仍然有效并且在范围内。在其范围之外访问本地变量是未定义的行为,但这完全没问题
在您的情况下,您可以安全地使用 &i
直到 i
有效。
现在,我们可以看到 i
的生命周期到 func1()
结束。因为,func2()
是从func1()
调用的,而func1()
还没有执行完,所以,i
仍然有效。
这就是为什么,通常将局部变量的地址传递给另一个函数是 通常 允许的(变量的生命周期尚未结束)但是,return
ing 地址局部变量的(在 return
之后,函数的局部变量不复存在)是 不允许的 。
TL;DR :您可以安全地使用 &i
作为 func2()
的参数,如此处所示。
如之前大多数答案所述,在您的特殊情况下将指针传递给 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;
}
这样的话,DataBuff
中的数据早就没有了,用ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr
中的指针将数据存入EEPROM
要修复此代码,至少需要声明 static UINT8 DataBuff[25];
此外,还应考虑声明 static valueObj_t NVMemObj
,因为我们不知道被调用的函数正在做什么指针。
简而言之:
TL;DR
尽管在 C 语言中是合法的,但我认为在函数调用中将指针传递给自动变量是有害的。您永远不知道(通常您也不想知道)被调用函数对传递的值究竟做了什么。当被调用的函数建立别名时,你就有大麻烦了。
只是我的 2 美分。
例如:
void func1(){
int i = 123;
func2(&i);
}
void func2(int *a){
*a = 456;
}
当func1
调用func2
时,指向局部变量的指针被传递给func2
——指针指向堆栈。这对 C 语言的规则安全吗?
谢谢。
是的,传递一个指向局部变量的指针是安全的,但你不能return从函数中传递一个指向自动局部变量的指针。
是的,您的代码是安全的。
只要对象的生命周期没有结束,像你这样传递局部变量是安全的。
i
的作用域是 func1
,它比对 func2
的调用更有效。所以绝对安全。
Is this safe for the rules of C?
你所做的是安全的,因为局部变量仍然有效并且在范围内。在其范围之外访问本地变量是未定义的行为,但这完全没问题
在您的情况下,您可以安全地使用 &i
直到 i
有效。
现在,我们可以看到 i
的生命周期到 func1()
结束。因为,func2()
是从func1()
调用的,而func1()
还没有执行完,所以,i
仍然有效。
这就是为什么,通常将局部变量的地址传递给另一个函数是 通常 允许的(变量的生命周期尚未结束)但是,return
ing 地址局部变量的(在 return
之后,函数的局部变量不复存在)是 不允许的 。
TL;DR :您可以安全地使用 &i
作为 func2()
的参数,如此处所示。
如之前大多数答案所述,在您的特殊情况下将指针传递给 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;
}
这样的话,DataBuff
中的数据早就没有了,用ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr
中的指针将数据存入EEPROM
要修复此代码,至少需要声明 static UINT8 DataBuff[25];
此外,还应考虑声明 static valueObj_t NVMemObj
,因为我们不知道被调用的函数正在做什么指针。
简而言之: TL;DR
尽管在 C 语言中是合法的,但我认为在函数调用中将指针传递给自动变量是有害的。您永远不知道(通常您也不想知道)被调用函数对传递的值究竟做了什么。当被调用的函数建立别名时,你就有大麻烦了。
只是我的 2 美分。