11.static(转)
本文转自:http://blog.csdn.net/keyeagle/article/details/6708077
google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大。所以,我这篇博文博采众家之长,把互联网上的资料整合归类,并亲手编写程序验证之。
C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错。伴随着不同源文件变量和函数之间的相互引用以及相互独立的关系,产生了extern和static关键字。下面,详细分析一下static关键字在编写程序时有的三大类用法:
一.static 全局变量
我们知道,一个进程在内存中的布局如图1所示:

其中.text段保存进程所执行的程序二进制文件,.data段保存进程所有的已初始化的全局变量,.bss段保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data段和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。
当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。
以下是一些示例程序
file1.h如下:
#include <stdio.h> void printStr();
我们在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr访问.
#include "file1.h" static char* hello = "hello cobing!"; void printStr()
{
printf("%s\n", hello);
}
file2.c是我们的主程序所在文件,file2.c中如果引用hello会编译出错
#include "file1.h" int main()
{
printStr();
printf("%s\n", hello);
return ;
}
报错如下:
[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改为下面的形式:
#include "file1.h" int main()
{
printStr();
return ;
}
则会顺利编译连接。
运行程序后的结果如下:
[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的内容如下:
#include "file1.h" void printStr()
{
int normal = ;
static int stat = ; //this is a static local var
printf("normal = %d ---- stat = %d\n",normal, stat);
normal++;
stat++;
}
为了便于比较,我定义了两个变量:普通局部变量normal和静态局部变量stat,它们都被赋予初值0;
file2.c中调用file1.h:
#include "file1.h" int main()
{
printStr();
printStr();
printStr();
printStr();
printf("call stat in main: %d\n",stat);
return ;
}
这个调用会报错,因为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,下面注掉这一行:
#include "file1.h" int main()
{
printStr();
printStr();
printStr();
printStr();
// printf("call stat in main: %d\n",stat);
return ;
}
[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如下:
#include <stdio.h> static int called();
void printStr();
file1.c如下:
#include "file1.h" static int called()
{
return ;
}
void printStr()
{
int returnVal;
returnVal = called();
printf("returnVal=%d\n",returnVal);
}
file2.c中调用file1.h中声明的两个函数,此处我们故意调用called():
#include "file1.h" int main()
{
int val;
val = called();
printStr();
return ;
}
编译时会报错:
[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:
#include "file1.h" int main()
{
printStr();
return ;
}
编译运行:
[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2
[liujx@server235 static]$ ./file2
returnVal=6
static函数可以很好地解决不同原文件中函数同名的问题,因为一个源文件对于其他源文件中的static函数是不可见的。
11.static(转)的更多相关文章
- 11.static关键字
1.用static修饰的方法,直接用类调用 2.static修饰的方法只能调用static方法,不能调用非 static属性和方法 ①因为static属性和方法在类没有实例化的时候调用 ②因为普通属 ...
- 15-static和extern关键字1-对函数的作用
一.extern与函数 如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.ob ...
- (转) C++ static、const和static const 以及它们的初始化
const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. static表示的是静态的.类的静态成员函数.静态成员变量是和类相关的,而不是和类的 ...
- Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)
1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...
- String,static,final
1. String 下面代码创建了几个对象? String s1 = new String("Hello"); String s2 = new String("Hello ...
- 007-对象—— static静态方法属性内存构成及使用方法讲解
<?php /* 7 对象 static静态方法属性内存构成及使用方法讲解 */ /*class a{ public $uname=11; static public function _a() ...
- java第4天:String static Arrays类,Math类
1 字符串的概述和特点 字符串一旦创建,是不可变的. 有双引号的就是字符串 *** 2 字符串的三种构造方法 2-1 第一种: 格式:String str = new String();| :-| 2 ...
- c语言中static关键字用法详解
个人总结: 1.C不是面向对象的,在c中static修饰的变量或函数仅在当前文件中使用 2.C可以对局部变量使用static修饰(注意面向对象的java则不行),其放在全局区一直存在 概述static ...
- C语言:static关键字用法
参考博客:https://blog.csdn.net/guotianqing/article/details/79828100 看个例子: #include <stdio.h> void ...
随机推荐
- [BZOJ 4144] Petrol
Link: BZOJ 4144 传送门 Solution: 一道不错的图论综合题 因为只询问关键点,因此重点是要求出关键点之间的最短路,以最短路建图 记$nst[i]$为离$i$最近的关键点:可以发现 ...
- 【Treap模板详细注释】BZOJ3224-普通平衡树
模板题:D错因见注释 #include<iostream> #include<cstdio> #include<cstring> #include<algor ...
- Problem Q: 零起点学算法12——求2个日期之间的天数
#include<stdio.h> int main() { int a1,b1,c1,a2,b2,c2,s; scanf("%d-%d-%d",&a1,&am ...
- Git学习笔记(一) 安装及版本库介绍
安装Git 最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑.不过,慢慢地有人把它移植到了Windows上.现在,Git可以在Linux.Unix.Mac和 ...
- GNS3 思科模块 说明
GNS3整合了如下的软件: Dynamips :一款可以让用户直接运行Cisco系统(IOS)的模拟器 Dynagen :是Dynamips的文字显示前端 Pemu : PIX防火墙设备模 ...
- HashMap深度解析(一)
HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构,我们总会在不经意间用到它,很大程度上方便了我们日常 开发.在很多Java的笔试题中也会被问到,最常见的,“H ...
- JVM OQL查询语言
OQL查询语言 SELECT Clause The SELECT clause determines what to extract from the heap dump. To display ob ...
- Install FileZilla in Ubuntu16.04
一.安装fileZilla $ sudo add-apt-repository ppa:n-muench/programs-ppa $ sudo apt-get update $ sudo apt-g ...
- 使用unity3d开发app
做过一些项目,参入过一些项目的计划安排.总觉得一些工具用起来很麻烦,要么是要收费,要么很大很重.没有针对小团队的简单易用的任务管理工具,也可能是找了些不能适合自己的习惯. 所有准备开始自己开发一款项目 ...
- vue-resource基本使用方法
一.vue-resource特点 1.体积小:vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多. 2.支持主流 ...