绊倒this question并阅读更多here(c ++但这个问题在C / C ++ AFAIN中的作用相同)我没有提到函数内部真正发生的事情。
void f(){
static int c = 0;
printf("%d\n",c++);
}
int main(){
int i = 10;
while(i--)
f();
return 0;
}
在此代码段中,c
生命周期是整个程序的执行,因此static int c = 0;
行在f()
的下一次调用中没有意义,因为c
已经定义的(静态)变量,赋值部分也是过时的(在下一次调用f()
中),因为它只在第一次发生。
那么,编译器会做什么?是否将f
拆分为2个函数 - f_init, f_the_real_thing
其中f_init
初始化并f_the_real_thing
打印,并调用1次f_init
并从此开始调用f_the_real_thing
1}}?
答案 0 :(得分:7)
第一项任务不是"已过时" - 确保c
在第一次调用f()
时为零。不可否认,这是静态的默认值:如果未指定初始化,则将初始化为零。但是static int c = 42
将确保c
在第一次调用函数时具有值42
,并且值序列将从那里继续。
static
关键字表示该变量具有静态存储持续时间。它只被初始化一次(因此在第一次调用函数时会有该值)但是更改会持续存在 - 每次检索到值时,检索到的值都将是最后一次存储在变量中。
所有编译器都将变量c
置于将存在的内存区域中 - 并保存上次设置的任何值 - 只要程序正在运行。具体如何实现取决于编译器。
但是,我从未见过编译器将函数的逻辑分成多个部分以容纳静态。
答案 1 :(得分:5)
虽然标准没有规定编译器必须如何实现行为,但大多数编译器都做了一件不那么复杂的事情:他们将c
放入静态内存段,并告诉加载器将{0}放入c
'的地址。这种方式f
直接进入预先初始化的c
,并继续打印和递增,就像声明行不在那里一样。
在C ++中,它可选择添加代码来初始化c
到静态初始化函数,该函数初始化所有静态变量。在这种情况下,不需要呼叫。
从本质上讲,这相当于c
从第一次调用f
之前的生命周期开始。您可以将c
的行为视为static
变量 f()
,其可见性受限于f()
的范围。
答案 2 :(得分:4)
C标准未指定必须如何实现静态存储持续时间所需的行为。
如果您对特定实现如何处理此问题感到好奇,那么您始终可以检查生成的程序集。
(请注意,在您的特定情况下,您的代码容易受到以c++
为中心的并发问题的影响,不一定是原子的;它还有int
溢出的漏洞,尽管i--
确实充当适当的终止条件。)