auto和static关键字
为什么不能从函数返回一个指向该函数局部变量的指针。
char *favorite_fruit() {
char deciduous[] = "apple";
return deciduous;
}
当进入该函数时,自动变量deciduous在堆栈中分配。当函数结束后,变量不复存在,它所占用的堆栈空间被回收,可能在任何时候被覆盖。这样,指针就失去了有效性(引用不存在的东西),被称为“悬垂指针”(dangling pointer)---它们并不引用有用的东西,而是悬在地址空间内。如果想返回一个指向在函数内部定义的变量的指针时,要把那个变量声明为static。这样就能保证该变量被保存在数据段中而不是堆栈中。该变量的生命期就和程序一样长,当定义该变量的函数退出时,该变量的值依然能保持。当该函数下一次进入时,该值依然有效。
/*
** return pointer of local auto variable.
*/
#include <stdio.h>
#include <stdlib.h>
char *favorite_fruit( void );
char *favorite_fruit_2( void );
int main( void ){
char *ret, *ret2;
ret = favorite_fruit();
ret2 = favorite_fruit_2();
printf( "ret = %p, ret = %s\n", ret, ret );
printf( "ret2 = %p, ret2 = %s\n", ret2, ret2 );
return EXIT_SUCCESS;
}
char *favorite_fruit( void ){
/*
** [Warning] address of local variable 'deciduous' returned[-Wreturn-local-addr]
** char deciduous[] = "apple";
*/
char deciduous[] = "apple";
printf( "1:decidous = %p, deciduous = %s\n", deciduous, deciduous );
return deciduous;
}
char *favorite_fruit_2( void ){
static char deciduous[] = "banana";
printf( "2:deciduous = %p, deciduous = %s\n", deciduous, deciduous );
return deciduous;
}
输出:
存储类型说明符auto通常由编译器设计者使用,用于标识符表的条目---它表示“在进入该块后,自动分配存储”(与编译时静态分配和堆上动态分配不同)。auto关键字只能用于函数内部。但是在函数内部声明的数据缺省就是这种分配。auto唯一的用途就是使你的声明更加清楚完整。
register int filbert;
auto int almond;
static int hazel;
而不是
register int filbert;
int almond;
static int hazel;
/*
** auto_var.c.
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
register int filbert = 1;
auto int almond = 2;
static int hazel = 3;
printf( "filbert = %d, almond = %d, hazel = %d\n", filbert, almond, hazel );
return EXIT_SUCCESS;
}
输出:/* ISO C99标准 */
/*
** auto_var.cpp.
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
register int filbert = 1;
/*
** auto int almond = 2;
** [Error] two or more data types in declaration of 'almond'
** [Error] 'almond' was not declared in this scope
*/
auto almond = 2;
static int hazel = 3;
printf( "filbert = %d, almond = %d, hazel = %d\n", filbert, almond, hazel );
return EXIT_SUCCESS;
}
输出:/* ISO C++11 标准 */
过程活动记录可能并不位于堆栈中。事实上,尽可能地把过程活动记录的内容放到寄存器中会使函数调用的速度更快,效果更好。SPARC架构引入了一个概念,称为“寄存器窗口”(register window),CPU在这个寄存器窗口中拥有一组寄存器,它们只用于保存过程活动记录中的参数。每当函数调用时,空的活动记录依然压入到堆栈中。当函数调用链非常深而寄存器窗口不够用时,寄存器的内容就会被保存到堆栈中保留的活动记录空间中,以便重新利用这些寄存器。
通常情况下,从堆栈中获取内存的速度比从堆上获取内存的速度更快一些。