转自:http://blog.csdn.net/keyeagle/article/details/6708077

看到这篇文章针对C语言的static关键字解释的比较好,这里转载过来。谢谢原作者分享。

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

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

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

一,static全局变量

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

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

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

以下是一些示例程序

file1.h如下:

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

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

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

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

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

报错如下:

[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 plaincopy
  1. #include "file1.h"
  2. int main()
  3. {
  4. printStr();
  5. return 0;
  6. }

则会顺利编译连接。

运行程序后的结果如下:
[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 plaincopy
  1. #include "file1.h"
  2. void printStr()
  3. {
  4. int normal = 0;
  5. static int stat = 0;    //this is a static local var
  6. printf("normal = %d ---- stat = %d\n",normal, stat);
  7. normal++;
  8. stat++;
  9. }

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

file2.c中调用file1.h:

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

这个调用会报错,因为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 plaincopy
  1. #include "file1.h"
  2. int main()
  3. {
  4. printStr();
  5. printStr();
  6. printStr();
  7. printStr();
  8. //  printf("call stat in main: %d\n",stat);
  9. return 0;
  10. }

[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 plaincopy
  1. #include <stdio.h>
  2. static int called();
  3. void printStr();

file1.c如下:

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

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

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

编译时会报错:

[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 plaincopy
  1. #include "file1.h"
  2. int main()
  3. {
  4. printStr();
  5. return 0;
  6. }

编译运行:

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

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

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

转载于:https://www.cnblogs.com/zhanglianpin/p/4622288.html

C语言中的static 详细分析 2014-10-11 15:15 143人阅读 评论(0) 收藏...相关推荐

  1. C语言中的static 详细分析

    google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大.所以,我这篇博文博采众家之长,把互 ...

  2. 2014/12/05 随笔 2014-12-05 12:50 26人阅读 评论(0) 收藏...

    有一段时间没写博客了..发现博客出现了两篇空的博文..不知道是怎么回事..估计是CSDN眼子了 - -, 最近因为忙于辞职的事情,还是比较纠结的... 嗯 这篇文章就分享一下在写代码的时候EF闹眼子的 ...

  3. linux分析字节序的分类及特点,计算机中的字节序详解 分类: 【Linux/Windows操作系统】 2015-01-07 21:54 97人阅读 评论(0) 收藏...

    我们都知道,内存中存储的是各种变量,各种奇葩东西,不用的变量占用不用的字长,例如在intel X86环境下,一个int占用两个字 0 1 2 3 4 5 6 7 8 9 0x30 0x31 0x32 ...

  4. 【C语言进阶深度学习记录】九 C语言中const的详细分析

    文章目录 1 const的分析 2 const本质的分析实验 2.1 代码案例分析 3 const修饰函数参数和返回值时的情况 3.1 代码案例分析 4 总结 1 const的分析 不管是C语言还是C ...

  5. C语言中的static 具体分析

    google了近三页的关于C语言中static的内容,发现可用的信息非常少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的刚開始学习的人来说參考性不是非常大.所以,我这篇博文博採众 ...

  6. c语言中的static变量和static函数

    在C语言中,static的字面意思很容易把我们导入歧途,其实它的修饰变量作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函 ...

  7. C/C++中Static的作用详述 在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。

    C/C++中Static的作用详述 在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏. 当我们同时编译多个文件时,所有未加s ...

  8. c语言中signal函数详细解释说明

    c语言中signal函数详细解释说明     对于 信号处理函数 位于 <signal.h> 中. void ( *signal( int sig, void (* handler)( i ...

  9. 2014年11月15日SIE赛意公司面试

    2014年11月15日SIE赛意公司面试 昨晚收到SIE(赛意)公司的面试通知,群面+单面共2个小时,今天中午就屁颠屁颠得跑到体育中心了.话休烦絮,直接进入正题. 1点半的面试,到公司门口已经1点15 ...

最新文章

  1. Science:最新发现哈希可能是大脑的通用计算原理!
  2. Google Map API 的基础使用
  3. 大促系统全流量压测及稳定性保证——京东交易架构
  4. 应用指定显示到副屏_广电演播领域与舞台LED租赁显示屏如何去选择LED小间距屏...
  5. java web中读取properties文件时的路径问题
  6. Spring学习(三)
  7. 51单片机18B20测温1602LCD显示
  8. reactnative资源
  9. Oracle数据库索引底层实现原理笔记
  10. python培训学堂怎么样_如何评价开智学堂开设的课程?
  11. 视频素材有水印怎么去除?
  12. jdbc——mysql学习
  13. boy模拟器 my_myboy模拟器中文下载
  14. 大疆2018校招笔试题
  15. define _WINSOCK_DEPRECATED_NO_WARNINGS
  16. 【域控】Windows Server 2012 AD域控搭建-系统安装及环境配置-1
  17. TCP的滑动窗口与拥塞窗口
  18. Python都能干什么
  19. Codeforces Round#768(Div.2)A-F
  20. 安川机器人编程指令含义

热门文章

  1. linux命令:xargs
  2. 计算机学习 -快捷键
  3. HP大中华区总裁孙振耀谈工作、职业与人生规划
  4. 【Python学习系列二十五】数据结构-有向图绘制
  5. Java实现算法导论中最长公共子序列(LCS)动态规划法
  6. servlet请求与响应的练习实例
  7. 通过GPG非对称加密工具验证ECharts发布版本实例演示,win10下Gnu Privacy Guard工具的安装和使用方法
  8. Python 微信机器人-用itchat库向好友发送名片、转发名片实例演示
  9. Altium designer 操作笔记
  10. CTFshow 信息收集 web20