在函数内部初始化静态变量会发生什么

时间:2017-07-25 11:00:37

标签: c static

绊倒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}}?

3 个答案:

答案 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--确实充当适当的终止条件。)