关闭

static的作用

标签: linux
144人阅读 评论(0) 收藏 举报
分类:

 google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大。所以,我这篇博文博采众家之长,把互联网上的资料整合归类,并亲手编写程序验证之。

         C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错。伴随着不同源文件变量和函数之间的相互引用以及相互独立的关系,产生了extern和static关键字。

        下面,详细分析一下static关键字在编写程序时有的三大类用法:

        一,static全局变量

           我们知道,一个进程在内存中的布局如图1所示:

      其中.text段保存进程所执行的程序二进制文件,.data段保存进程所有的已初始化的全局变量,.bss段保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data段和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。

     当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。

以下是一些示例程序

file1.h如下:

[cpp] view plain copy
  1. #include <stdio.h>  
  2.   
  3. void printStr();  

我们在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr访问.

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. static char* hello = "hello cobing!";  
  4.   
  5. void printStr()  
  6. {  
  7.     printf("%s\n", hello);  
  8. }  

file2.c是我们的主程序所在文件,file2.c中如果引用hello会编译出错

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.     printStr();  
  6.     printf("%s\n", hello);  
  7.     return 0;  
  8. }  

报错如下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
file2.c: In function ‘main’:
file2.c:6: 错误:‘hello’ 未声明 (在此函数内第一次使用)
file2.c:6: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
file2.c:6: 错误:所在的函数内只报告一次。)


如果我们将file2.c改为下面的形式:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.     printStr();  
  6.     return 0;  
  7. }  

则会顺利编译连接。

运行程序后的结果如下:
[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
[liujx@server235 static]$ ./file2
hello cobing!

上面的例子中,file1.c中的hello就是一个静态全局变量,它可以被同一文件中的printStr调用,但是不能被不同源文件中的file2.c调用。

 

      二,static局部变量

      普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。局部变量也可以在堆上动态分配,但是记得使用完这个堆空间后要释放之。

       static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有如下几个区别:

           1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。

           2)访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。

           3):静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。
以下是一些示例程序:

     file1.h的内容和上例中的相同,file1.c的内容如下:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. void printStr()  
  4. {  
  5.     int normal = 0;  
  6.     static int stat = 0;    //this is a static local var  
  7.     printf("normal = %d ---- stat = %d\n",normal, stat);  
  8.     normal++;  
  9.     stat++;  
  10. }  

为了便于比较,我定义了两个变量:普通局部变量normal和静态局部变量stat,它们都被赋予初值0;

file2.c中调用file1.h:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.  printStr();  
  6.  printStr();  
  7.  printStr();  
  8.  printStr();  
  9.  printf("call stat in main: %d\n",stat);  
  10.  return 0;  
  11. }  

这个调用会报错,因为file2.c中引用了file1.c中的静态局部变量stat,如下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
file2.c: In function ‘main’:
file2.c:9: 错误:‘stat’ 未声明 (在此函数内第一次使用)
file2.c:9: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
file2.c:9: 错误:所在的函数内只报告一次。)

编译器说stat未声明,这是因为它看不到file1.c中的stat,下面注掉这一行:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.     printStr();  
  6.     printStr();  
  7.     printStr();  
  8.     printStr();  
  9. //  printf("call stat in main: %d\n",stat);  
  10.     return 0;  
  11. }  

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
[liujx@server235 static]$ ./file2
normal = 0 ---- stat = 0
normal = 0 ---- stat = 1
normal = 0 ---- stat = 2
normal = 0 ---- stat = 3

运行如上所示。可以看出,函数每次被调用,普通局部变量都是重新分配,而静态局部变量保持上次调用的值不变。

需要注意的是由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。需要多加注意。


       三,static函数
              相信大家还记得C++面向对象编程中的private函数,私有函数只有该类的成员变量或成员函数可以访问。在C语言中,也有“private函数”,它就是接下来要说的static函数,完成面向对象编程中private函数的功能。

            当你的程序中有很多个源文件的时候,你肯定会让某个源文件只提供一些外界需要的接口,其他的函数可能是为了实现这些接口而编写,这些其他的函数你可能并不希望被外界(非本源文件)所看到,这时候就可以用static修饰这些“其他的函数”。

           所以static函数的作用域是本源文件,把它想象为面向对象中的private函数就可以了。

下面是一些示例:

file1.h如下:

[cpp] view plain copy
  1. #include <stdio.h>  
  2.   
  3. static int called();  
  4. void printStr();  

file1.c如下:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. static int called()  
  4. {  
  5.     return 6;  
  6. }  
  7. void printStr()  
  8. {  
  9.     int returnVal;  
  10.     returnVal = called();  
  11.     printf("returnVal=%d\n",returnVal);  
  12. }  

file2.c中调用file1.h中声明的两个函数,此处我们故意调用called():

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.     int val;  
  6.     val = called();  
  7.     printStr();  
  8.     return 0;  
  9. }  

编译时会报错:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
file1.h:3: 警告:‘called’ 使用过但从未定义
/tmp/ccyLuBZU.o: In function `main':
file2.c:(.text+0x12): undefined reference to `called'
collect2: ld 返回 1

因为引用了file1.h中的static函数,所以file2.c中提示找不到这个函数:undefined reference to 'called'

下面修改file2.c:

[cpp] view plain copy
  1. #include "file1.h"  
  2.   
  3. int main()  
  4. {  
  5.     printStr();  
  6.     return 0;  
  7. }  

编译运行:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
[liujx@server235 static]$ ./file2
returnVal=6

       static函数可以很好地解决不同原文件中函数同名的问题,因为一个源文件对于其他源文件中的static函数是不可见的。

有疏漏的地方望各位多多指教~~

0
0
查看评论

java 理解static代码块的作用

static代码块一般用于初始化类中的静态变量,该静态代码块在类加载过程中的初始化阶段执行,并且只执行一次。 使用static静态代码块进行初始化与直接在定义变量的时候初始化效果是一样的,但是它们的先后顺序可能会对变量的值造成影响。 示例: public cla...
  • lxyzhu
  • lxyzhu
  • 2014-11-12 12:05
  • 3148

[程序员面试题]C/C++中static的作用

面试题:static有什么作用? 答:在C语言中,static主要定义全局静态变量,定义局部静态变量,定义静态函数  一、       定义全局静态变量 :在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点:...
  • leo115
  • leo115
  • 2012-10-18 14:02
  • 14191

static修饰符的作用及应用

/* static 修饰符 1.数据共享成员变量(实例变量)和静态变量(类变量)的区别 1.两个变量的生命周期不同 成员变量随对象的创建而存在,随对象被回收而释放 静态变量随类的加载而存在,随类的消失而消失 2.调用方式不同 成员变量只能被对象调用 静态变量还可以被类名调用 3.数...
  • u012768347
  • u012768347
  • 2016-03-27 14:12
  • 2217

Java中static关键字的作用

Java中static关键字的作用
  • jsqfengbao
  • jsqfengbao
  • 2015-03-29 08:45
  • 17613

JAVA中理解static修饰符的作用

是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只要程序在运行,那么这块内存就会一直存在。这样做有什么意义呢? 在Java程序里面,所有的东西都...
  • u013440660
  • u013440660
  • 2014-05-30 21:02
  • 1887

static的三个作用

static的三个作用:       这个简单的问题很少有人能回答完全。 在C语言中,关键字static有三个明显的作用:      1 在函数体,一个被声明为静态的变量在这一函数被调...
  • cjjwwss
  • cjjwwss
  • 2014-07-22 17:17
  • 657

Java中static的作用详解

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。  被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。 只要这个类被加载,Jav...
  • u010931123
  • u010931123
  • 2017-03-07 17:49
  • 826

static、final、transient等关键字的作用

staticstatic表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块 被static修饰后的成员,在编译时由内存分配一块内存空间,直到程序停止运行才会释放,那么就是说该类的所有对象都会共享这块内存空间。 在java类库当中有很多类成员都声明为stati...
  • zhangfengzhang123
  • zhangfengzhang123
  • 2017-02-28 17:11
  • 761

static及其作用域

<br />一、面向过程设计中的static 1、静态全局变量 在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下: //Example 1#include <iostream.h>void ...
  • celerylxq
  • celerylxq
  • 2011-01-24 09:12
  • 10372

static变量有什么作用

关键字static的意思是静态,有3个明显作用: 1)在函数体内,静态变量具有"记忆"功能。即在函数被调用过程中,一个被声明为静态变量的值维持不变。   static局部变量和普通局部变量的区别:static局部变量只被初始化一次,下一次的运算依据上一次的结果值。
  • xiaominkong123
  • xiaominkong123
  • 2016-06-08 11:32
  • 3333
    个人资料
    • 访问:42956次
    • 积分:2611
    • 等级:
    • 排名:第16507名
    • 原创:200篇
    • 转载:85篇
    • 译文:0篇
    • 评论:3条
    最新评论