天天看点

【C/C++】关键字static

参考自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/19/2598815.html (华山大师兄)

这里我们只讨论了C语言的static

首先我们回顾一下各种变量在内存中的位置:

【C/C++】关键字static

BSS和DATA段都属于静态数据区,在进程运行过程中,静态数据区的数据始终存在。静态全局变量和其他全局变量的存储地点没有区别,因此还是在BSS和DATA中。但是,静态全局变量仅在定义它的源文件中有效,其他文件即使用extern声明也没法使用他。准确地说作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些代码行也不能使用它。

1、静态的全局变量和函数

当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。

举个例子:

//a.c
#include <stdio.h>

char a = 'A';               // global variable
void msg()
{
     printf("Hello\n");
}
           
//a.h
#ifndef _A_H_
#define _A_H_

extern char a;
void msg();

#endif
           
#include <stdio.h>
#include "a.h"

//b.c
int main()
{
     printf("%c ", a);
     msg();
     return 0;
}
           

以上代码成功编译连接后,输出 A Hello。

我们知道,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件b.c是可见的。

但是,如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,b.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名全局变量,而不必担心命名冲突。

2、静态的局部变量

static局部变量在函数内定义,它的生存期为整个程序运行过程,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。

举个例子:

#include <stdio.h>

int fun(){
    static int count = 10;       //在第一次进入这个函数的时候,变量a被初始化为10!并接着自减1,以后每次进入该函数,a
    return count--;              //就不会被再次初始化了,仅进行自减1的操作;在static发明前,要达到同样的功能,则只能使用全局变量:    

}

int count = 1;

int main(void)
{
     printf("global\t\tlocal static\n");
     for(; count <= 10; ++count)
               printf("%d\t\t%d\n", count, fun());
     return 0;
}
           

输出如下:

【C/C++】关键字static

基于以上两点,我们得出:把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

3、未手动初始化的static变量和全局变量默认初始化为0

未手动初始化的static变量和全局变量都存储在 BSS 段,该区域的变量的值都为0。

某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘\0’;不妨做个小实验验证一下。

#include <stdio.h>

int a;

int main()
{
     int i;
     static char str[10];
     printf("integer: %d; string: (begin)%s(end)", a, str);
     return 0;
}
           

运行结果为:integer: 0; string: (begin) (end)