函数内部的静态变量

打印出来的是什么? 66还是67? 为什么?

void foo()
{
static int x = 5;
x++;
printf("%d", x);
}


int main()
{
foo();
foo();
return 0;
}
223840 次浏览

67

编译器安排静态变量初始化不会在每次输入函数时发生

这里有两个问题,生存期和范围。

变量的作用域是可以看到变量名的地方。在这里,x仅在函数 foo()内可见。

变量的生命周期是它存在的周期。如果定义 x时没有使用关键字 static,那么生存期将从 foo()的入口到 foo()的返回; 因此每次调用时它将被重新初始化为5。

关键字 static的作用是将变量的生命周期延长到程序的生命周期; 例如,初始化只发生一次,然后变量保留它的值——不管它是什么——在所有未来对 foo()的调用中。

让我们读一下 关于静态变量的维基百科文章..。

静态局部变量: 声明为函数内静态的变量是静态分配的,同时具有与自动局部变量相同的作用域。因此,无论函数在一次调用期间输入到静态局部变量中的值是什么,当再次调用该函数时仍然存在。

输出将是 6 7。静态变量(无论是否在函数内部)在该转换单元中的任何函数执行之前只初始化一次。之后,它保留它的值,直到修改。

您将得到67打印,因为很容易测试,原因如下: 当第一次调用 foo时,静态变量 x 被初始化为5。然后增加到6并打印出来。

下一个打到 foo的电话。程序跳过静态变量初始化,而是使用上次分配给 x 的值6。执行正常进行,给出值7。

这等同于有以下方案:

static int x = 5;


void foo()
{
x++;
printf("%d", x);
}


int main()
{
foo();
foo();
return 0;
}

Static 关键字在程序中的作用就是告诉编译器(本质上)“嘿,我这里有一个变量,我不想让其他人访问,不要告诉其他人它的存在”。

在一个方法内部,static 关键字告诉编译器和上面一样,但是,“不要告诉任何人它存在于这个函数之外,它应该只能在这个函数内部访问”。

希望这个能帮上忙

6 7

X 是一个只能从 foo ()中看到的全局变量。5是它的初始值,存储在。代码的数据部分。任何后续修改都会覆盖以前的值。在函数体中没有生成赋值代码。

函数中的静态变量只要程序运行,就有生命周期。它不会在每次调用函数时被分配,在函数返回时被释放。

瓦迪克,

为什么... ? 原因是静态变量只初始化一次,并在整个程序中保持它的值。 意味着,可以在函数调用之间使用静态变量。 也可以用来计算“一个函数被调用了多少次”

main()
{
static int var = 5;
printf("%d ",var--);
if(var)
main();
}

答案是5-4-3-2-1而不是5-5-5-5-5... (无限循环)就像你期望的那样。 同样,原因是静态变量初始化一次,当下次调用 main ()时 它不会被初始化为5,因为它已经在程序中被初始化了。所以我们可以改变这个值,但是不能重新初始化。这就是静态变量的工作原理。

或者你可以考虑根据存储: 静态变量存储在程序的数据段,变量存储在数据段初始化一次。在初始化之前,它们保存在 BSS 部分。

反过来,自动(本地)变量存储在栈上,栈上的所有变量重新初始化时,函数被调用为新的 FAR (函数激活记录)被创建。

为了更好地理解,请不要使用“ static”来做上面的示例,并让您知道输出是什么。这让你明白了这两者之间的区别。

谢谢 贾韦德

产出 : 67

原因 : 静态变量只初始化一次(不同于自动变量) ,并且在运行时会跳过静态变量的进一步定义。如果它不是手动初始化,它会自动被值0初始化。 那么,

void foo() {
static int x = 5; // assigns value of 5 only once
x++;
printf("%d", x);
}


int main() {
foo(); // x = 6
foo(); // x = 7
return 0;
}

6和7 因为静态变量只初始化一次, 所以5 + + 在第一次调用时变成了6 6 + + 在第二次呼叫时变成7 注意——当第二次调用发生时,x 值为6,而不是5,因为 x 是静态变量。

输出: 6,7

原因

x的声明在 foo内部,但是 x=5的初始化发生在 foo之外!

我们需要明白的是

static int x = 5;

是不一样的

static int x;
x = 5;

其他的回答使用了这里的重要词语: scope 和 life,并指出 x的作用域是从它在函数 foo中的声明开始到函数 foo的结束。例如,我通过将声明移动到函数的末尾来检查,这使得 xx++;语句中没有声明。

因此,该语句的 static int x(scope)部分实际上应用于您读取它的地方,也就是函数 在里面的某个地方,并且仅从那里开始,而不是在函数内部的它之上。

然而,语句的 x = 5(生命周期)部分是 变量的初始化,并作为程序加载的一部分发生函数的 在外面。当程序加载时,变量 x的值为 5

我在其中一条评论中读到: “ 此外,这并没有解决真正令人困惑的部分,即在后续调用中跳过初始化器这一事实。”在所有通话中都被跳过。变量的初始化超出了函数代码的范围。

理论上,无论是否调用 foo,都可以设置值5,尽管如果不在任何地方调用,编译器可能会优化函数。在调用 foo 之前,值5应该在变量中。

foo内部,static int x = 5;语句根本不可能生成任何代码。

当我将函数 foo放入我的程序中时,我发现了 x使用的地址,然后(正确地)猜测,如果我再次运行该程序,将使用相同的位置。下面的部分屏幕截图显示,即使在第一次调用 foo之前,x的值也是 5

Break Point before first call to foo

至少在 C + + 11中,当用于初始化局部静态变量的表达式不是“ Constexpr”(编译器无法计算)时,那么必须在第一次调用函数时进行初始化。最简单的示例是直接使用参数来初始化局部静态变量。因此,编译器必须发出代码来猜测调用是否是第一个调用,这反过来又需要一个局部布尔变量。我已经编译了这样的例子,并通过查看汇编代码来验证这是否正确。例子可以是这样的:

void f( int p )
{
static const int first_p = p ;
cout << "first p == " << p << endl ;
}


void main()
{
f(1); f(2); f(3);
}

当然,如果表达式是“ conexpr”,那么就不需要这样做,变量可以通过使用编译器在输出汇编代码中存储的值在程序加载时进行初始化。

分享一下我在这一点上学到的东西。

static声明说明符,分为三类:

  • 存储类 : 有四个类: auto、 static、 extern 和 register。
  • 类型限定符 : 类似关键字: const、 volatile 等。
  • 类型说明符 : 如关键字: void、 char、 short、 int 等。

所以 static储存类别。它将决定 C 程序中每个变量的以下三个属性。

  • 存储持续时间 : 表示为变量分配内存和释放内存的时间。只要程序运行,具有 static存储持续时间的变量就保持在相同的内存位置。
  • Scope : 表示可以访问变量的程序文本部分。
  • Link : 表示程序的不同部分(或文件)可以共享变量的程度。

static存储类对变量有不同的影响,这取决于它是在块外声明的还是在块内声明的。让我们关注在块中声明 static变量的情况(本文讨论的那个)。

  • 块中的静态变量初始化为 只有一次
  • 如果一个函数被多次调用,那么该函数的所有调用将使静态块变量为 分享

这种理解是基于“ C 编程的现代方法”一书