不平静的 Static

#static #C #C语言 #作用域 #编译 #静态变量

static 在中文里的意思是静止的,然而,它却并不安分。在C语言中,我们可以使用它来声明静态变量。

在内存中,其存储区域主要分为三大块:

  • 栈,用来存储局部变量,其生命周期维持在所在函数的生命周期内。当函数运行结束,其存储的内容会自动销毁。
  • 堆,用于存储mallocnew动态分配的内存空间,其生命周期由freedelete决定。
  • 静态区,存储自动全局变量与static关键字声明的变量。其生命周期在程序运行过程持续存在。

讲了这么多,关键是最后一句其生命周期在程序运行过程持续存在

可以先看一下下面这个程序:

#include "stdio.h"
int fun(void)
{
    static int n = 0;
    n++;
    return n;
}
int main(void)
{
    int i = 0;
    for(i = 0; i < 10; i++)
    {
        fun();
    }
    printf("%d", fun());
    return 0;
}

程序最终的输出结果是什么呢? 0 还是什么?

在函数fun中,n虽然作用域仅限制于fun函数中,但是因为被static声明为静态变量,因此其生命周期会持续存在,因此在函数执行完了以后,n并没有被销毁。第二次调用fun函数时,n已经不是等于 0 了。

此外,如果在声明时静态变量时不赋初值(把n = 0=0去掉)可以吗?我试了多种编译器,证明声明静态变量是会被默认赋值 0 的。不过这样写代码可读性不好,容易造成误解。所以,一般还是给它赋个初值吧~

关于上面那个程式,如果在n++前加上n = 0,结果又会等于什么呢?可以先思考一下,然后运行看看对不对~

static出了在函数内部声明局部的静态变量外,也可以用于在函数外声明全局的静态变量。但是,从表面上看,似乎看不出有有什么作用(已经是全局变量,加不加都是生命周期在程序运行过程持续存在)。

但是如果你进行多个文件编译,就可以看出区别了。

A文件(a.c):

int j = 1;  
int fun(void)  
{  
    return j;  
}

B文件(b.c):

#include "stdio.h"  
int j;  
extern int fun();  
int main(void)  
{  
    j = 2;  
    printf("%d", fun());  
    return 0;  
}

如果在VC中将这两个文件放在同一个空间内编译(或在 gcc 中一起编译)。编译器将会报出一个错误:“int j” 已经在 a.obj 中定义。因为你将两个相同的变量在同样的作用域里声明了两次。

那么,这时,你在其中一个int j;前加上static,然后再编译,咦?错误没了。运行,结果等于1。也就是,a 文件里的 j 已经不是 b 文件里的j 了~

在这里,static还具备另一个作用——限定作用域。它把被声明的变量的作用域限定在了本文件中了。因此,a 文件的 j 也就不会与之冲突了。

static 也可以被用来声明函数,有时为了开发一个项目,会多人多文件的协作开发,但是有些函数只是内部调用,为了避免与别人定义的函数冲突,可以在前面加上 static ,把函数的作用域限定在本文件中。

细心的同学可能会发现,在B文件中,有这么一句:

extern int fun();

extern 又是用来做什么的?这个,下次再说~今天就先这样~

PS:在 C++ 中,又对 static 的功能做了扩充(可怜的 static ……T_T),有机会再我再去整理一下~