static 初始化变量初始化的问题

java中普通变量、静态变量、静态代码块初始化的顺序辨析
1.普通变量的初始化
看如下程序
class Window{ &
& & public Window(int maker) { &
& & & & System.out.println(&Window(&+maker+&)&); &
class House{ &
& & Window w1 = new Window(1); &
& & public House() { &
& & & & System.out.println(&House()&); &
& & & & w3 = new Window(33); &
& & Window w2 = new Window(2); &
& & void f(){ &
& & & & System.out.println(&f()&); &
& & Window w3 = new Window(3); &
public class Test { &
& & public static void main(String[] args) { &
& & & & House h = new House(); &
& & & & h.f(); &
& 结果如下: &
Window(1) &
Window(2) &
Window(3) &
Window(33) &
分析:普通变量在类中的任何方法(包括构造函数)之前初始化(规则一)。
2.静态变量的初始化
class Bowl{ &
& & public Bowl(int maker) { &
& & & & System.out.println(&Bowl(&+maker+&)&); &
& & void f1(int maker){ &
& & & & System.out.println(&f1(&+maker+&)&); &
class Table{ &
& & static Bowl bowl1 = new Bowl(1); &
& & static Bowl bowl2 = new Bowl(2); &
& & public Table() { &
& & & & System.out.println(&Table()&); &
& & & & bowl2.f1(1); &
& & void f2(int maker){ &
& & & & System.out.println(&f2(&+maker+&)&); &
class Cupboard{ &
& & Bowl bowl3 = new Bowl(3); &
& & static Bowl bowl4 = new Bowl(4); &
& & static Bowl bowl5 = new Bowl(5); &
& & public Cupboard() { &
& & & & System.out.println(&cupboard()&); &
& & & & bowl4.f1(2); &
& & void f3(int maker){ &
& & & & System.out.println(&f3(&+maker+&)&); &
public class Test { &
& & static Table table = new Table(); &
& & static Cupboard cupboard = new Cupboard(); &
& & public static void main(String[] args) { &
& & & & System.out.println(&creating new cupboard() in main&); &
& & & & new Cupboard(); &
& & & & System.out.println(&creating new cupboard() in main&); &
& & & & new Cupboard(); &
& & & & table.f2(1); &
& & & & cupboard.f3(1); &
& & & & &&
& 结果如下: &
cupboard() &
creating new cupboard() in main &
cupboard() &
creating new cupboard() in main &
cupboard() &
*/&span style=&color:#ff0000&& &
1.首先程序总共有4个类(Bowl,Table,Cupboard,Test),Bowl没有静态变量和静态方法;Table中有静态变量bowl1、bowl2;Cupboard中有普通变量bowl3,静态变量bowl4、bowl5;Test中有静态变量table、cupboard。
2.根据规则:使用static命名的变量或者使用static{}包括起来的区域,都在类被加载时进行初始化(规则二)。
3.首先加载Test,需要初始化table变量,加载Table类。Table类中有静态变量bowl1,bowl2,初始化它们,输出&Bowl(1),Bowl(2)&,再调用构造函数来new对象,输出&Table(),f1(1)&。然后加载Cupboard类,初始化静态变量bowl4,bowl5,输出&Bowl(4),Bowl(5)&,调用构造函数来new对象,首先初始化普通变量bowl3,输出&Bowl(3)&,然后构造函数,输出&cupboard(),f1(2)&。
4.执行main方法,先输出&creating new cupboard() in main&,执行new Cupboard(),这时静态变量都初始化了,不必继续初始化。初始化一般变量bowl3,输出&bowl3&,然后调用构造函数,输出&cupboard(),f1(2)&。在输出&creating new cupboard() in main&,同理输出&bowl3,cupboard(),f1(2)&,最后继续执行main函数,输出&f2(1),f3(1)&。
3.静态代码块的初始化
class Spoon{ &
& & public Spoon(int maker) { &
& & & & System.out.println(&Spoon(&+maker+&)&); &
& & static Spoon s = new Spoon(1); &
& & static{ &
& & & & System.out.println(&static code &); &
& & & & i = 47; &
& & } & &&
public class Test { &
& & public static void main(String[] args) { &
& & & & new Spoon(2); &
Spoon(1) &
static code &&
Spoon(2) &
&如果写成 &
& & static{ &
& & & & System.out.println(&static code &); &
& & & & i = 47; &
& & static Spoon s = new Spoon(1); &
结果为: &
static code &&
Spoon(1) &
Spoon(2) &
分析:静态代码块跟静态变量都是类加载时进行初始化的(同等条件下,初始化顺序由书写顺序决定)
4.非静态代码块
class Spoon{ &
& & public Spoon(int maker) { &
& & & & System.out.println(&Spoon(&+maker+&)&); &
& & static Spoon s = new Spoon(1); &
& & static{ &
& & & & System.out.println(&static code &); &
& & & & i = 47; &
& & //非静态代码块与直接为变量赋值效果相同,只不过可以写更为复杂的代码,非静态代码块一般用于内部类中 &
& & & & System.out.println(&non-static instatnce&); &
& & & & a = 1; &
public class Test { &
& & public static void main(String[] args) { &
& & & & new Spoon(2); &
& & & & new Spoon(3); &
non-static instatnce &
Spoon(1) &
static code &&
non-static instatnce &
Spoon(2) &
non-static instatnce &
Spoon(3) &
1.main函数执行new Spoon(2)语句,首先加载Spoon类,先初始化静态变量s,s调用new Spoon(1),此时类Spoon已经加载,所以不用管静态变量和静态代码块了,然后调用非静态代码块和构造函数,输出&non-static code,spoon(1)&。
2.初始化静态代码块,输出&static code&。
3.执行new spoon(2)语句输出&non-static instatnce,Spoon(2)&。
4.执行&new spoon(3)&语句输出&non-static instatnce,Spoon(3)&。
可以尝试调换静态变量s和静态代码块的顺序,发现只是1和2的先后顺序改变而已。
在看下面这个程序
&span style=&font-size:18px&&class T{ &
& & public T() { &
& & & & System.out.println(&T constructor&); &
class Spoon{ &
& & public Spoon(int maker) { &
& & & & System.out.println(&Spoon(&+maker+&)&); &
& & //非静态代码块与直接为变量赋值效果相同,只不过可以写更为复杂的代码,非静态代码块一般用于内部类中 &
& & & & System.out.println(&non-static instatnce&); &
& & & & a = 1; &
& & T t1 = new T(); &
public class Test { &
& & public static void main(String[] args) { &
& & & & new Spoon(2); &
non-static instatnce&
T constructor&
通过这个程序,可以发现非静态变量和非静态代码块顺序由书写顺序决定。
& 以Dog类为例
& 1.当第一次执行到需要使用Dog类时(如Dog d = new Dog),java首先通过寻找classpath来找到Dog.class,进行加载.
& 2.初始化Dog类的静态变量和静态代码块(按书写顺序,若静态变量或代码块中还有new Dog,此时不用再管静态变 & 量和代码块了,如第五个程序中的&static Spoon s = new Spoon(1)&)。
& 3.给类分配足够大的内存空间,初始化非静态变量和非静态代码块(顺序由书写顺序决定)
& 4.最后执行Dog类的构造函数。
& 5.以后如果还要new Dog类对象时(不是第一次使用了),重复3和4的步骤,不会再去初始化静态变量和静态代码 & & 块了。
& &大家可以自己写程序实验一下。
6.子类继承父类时的初始化顺序
& &1.系统启动时,首先初始化父类和子类的static变量和块
& &2.初始化父类的普通变量,调用父类的构造函数
& &3.初始化子类的普通变量,调用子类的构造函数
由于个人能力有限,第一次学习只了解这些了,有什么错误,请多多指教。
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
空间积分0 信誉积分381 UID阅读权限10积分63帖子精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
白手起家, 积分 63, 距离下一级还需 137 积分
帖子主题精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
论坛徽章:0
本帖最后由 crazyhadoop 于
18:13 编辑
以前被问过一个多线程环境中的static变量问题,到现在一直没搞明白,
今天写了一小段代码,但解释不清,大家帮忙看看吧
multiThread_staticVar.c#include &stdio.h&& && && && && && && && && && && && && && && && && && && && && &
#include &pthread.h&
#include &unistd.h&
#include &sys/types.h&
#include &sys/syscall.h&
#define INIT 1
#define MAX 10
//static int v = INIT;
void *f (void *arg)
{
&&static int v = INIT;
&&printf(&Thread ID = %ld, arg = %d, v = %d\n&, syscall(SYS_gettid), *(int *)arg, v);
&&while (v & MAX) {
& & v += *(int *)
//& & printf(&v = %d\n&, v);
& & printf(&Thread ID = %ld, arg = %d, v = %d\n&, syscall(SYS_gettid), *(int *)arg, v);
& & sleep(1);
&&}
&&return NULL;
}
int main (int argc, char const *argv[])
{
&&pthread_t t1, t2;
&&int a = 2, b = 1;
&&pthread_create(&t1, NULL, f, &a);
&&pthread_create(&t2, NULL, f, &b);
&&pthread_join(t1, NULL);
&&pthread_join(t2, NULL);
&&return 0;
}复制代码程序运行的结果如下~$ ./multiThread_staticVar
Thread ID = 3467, arg = 2, v = 1
Thread ID = 3467, arg = 2, v = 3
Thread ID = 3468, arg = 1, v = 1
Thread ID = 3468, arg = 1, v = 4
Thread ID = 3467, arg = 2, v = 6
Thread ID = 3468, arg = 1, v = 7
Thread ID = 3467, arg = 2, v = 9
Thread ID = 3468, arg = 1, v = 10复制代码可以看到,线程3467中static变量v被初始化为1,然后加上了2,变为3,然后sleep,线程3468开始执行,这时打印的v的值还是1,但执行v += *(int *)复制代码即v += 1;后v的值变为4,则v的值变化之前是3,即线程3467 sleep时的值,这里我不理解:当线程3468开始执行f()的时候,v的值应该已经是3,但打印出来是1,但执行v += *(int *)复制代码却变为4,这明明又是在线程3467的执行结果上加了1,为什么?还有,v是static变量,应该只初始化一次,但线程3468开始执行f()时v的值是1,即为其初始化的值,请各位朋友看看
& &多线程并发取数据竞争。
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
空间积分0 信誉积分104 UID阅读权限20积分874帖子精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
丰衣足食, 积分 874, 距离下一级还需 126 积分
帖子主题精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
论坛徽章:0
lz刚开始学多线程吧?最基本的同步问题,操作v的时候要加锁的。你的问题就是不加锁的关系。
空间积分0 信誉积分381 UID阅读权限10积分63帖子精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
白手起家, 积分 63, 距离下一级还需 137 积分
帖子主题精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
论坛徽章:0
samlumengjun
你没有仔细看我的问题,我这里问的是static变量的初始化,不是加锁不加锁
空间积分0 信誉积分104 UID阅读权限20积分874帖子精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
丰衣足食, 积分 874, 距离下一级还需 126 积分
帖子主题精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
论坛徽章:0
& & 你这个就是没加锁的问题,一开始创建的2个线程几乎是同时访问v的,所以都读到了初始值1,之后由于sleep的存在,就正常了,简单点验证一下,你就在第一和第二个线程创建函数中间加个sleep就明白了,或者就干脆在线程函数里读写v的时候加锁。
总评分:&可用积分 + 1&
空间积分0 信誉积分381 UID阅读权限10积分63帖子精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
白手起家, 积分 63, 距离下一级还需 137 积分
帖子主题精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
论坛徽章:0
samlumengjun
果然是这样,多谢!
我想看看多线程环境中的static变量的初始化,现在看来,多线程环境下static变量仍然只初始化一次,但这个是怎么做到的呢?
static变量被第一个线程初始化以后,第二个线程是如何知道这个static变量已被初始化的呢?
空间积分0 信誉积分104 UID阅读权限20积分874帖子精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
丰衣足食, 积分 874, 距离下一级还需 126 积分
帖子主题精华可用积分874 专家积分0 在线时间831 小时注册时间最后登录
论坛徽章:0
静态变量是在编译初始化的之后仅仅是访问或者修改。
空间积分0 信誉积分381 UID阅读权限10积分63帖子精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
白手起家, 积分 63, 距离下一级还需 137 积分
帖子主题精华可用积分63 专家积分0 在线时间240 小时注册时间最后登录
论坛徽章:0
samlumengjun
全局变量和静态变量的初始化都是编译期就完成,明白了,多谢
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处当前位置: >
> 多线程编程中使用STATIC局部变量问题以下函数会在一个多线程程序中被调用,会产生什么问题intG
多线程编程中使用STATIC局部变量问题以下函数会在一个多线程程序中被调用,会产生什么问题intG
paniel & at
多线程编程中使用STATIC局部变量问题以下函数会在一个多线程程序中被调用,会产生什么问题 
int & GetMsgId(char & *MsgIdBuf)
& static & unsigned & int & sequencenum & = & 0; &
& //序列号。到了9999自动丛0开始 &
& sprintf(MsgIdBuf, &
&%04d &,sequencenum++);
& if & (sequencenum & &
& sequencenum & = & 0;
& return & 0;
当多个线程“抢着”修改sequencenum变量时,会发生问题。
因为它是静态的,所以多个线程实质上共享了它,但在访问它时却没有加锁。
panjin72 & &
& & (0)(0)就是你想要的和实际得到的不一定符合
panjinfeng & &
& & (0)(0)加锁,要看lz的需求了,
panjiling & &
& & (0)(0)静态变量的初始化,放到函数中
这没有问题panjiexy & &
& & (0)(0)
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-页面导航:
→ 正文内容 C++static关键字
C++的static关键字及变量存储位置总结
今天看博文时,看到了c++的static关键字的一些总结,还涉及到了一些代码的存储位置;接下来为您详细呈现
今天看博文时,看到了c++的static关键字的一些总结,还涉及到了一些代码的存储位置,为了有时间的时候能够看一下,还是自己把它给摘抄下来吧。C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。 一、面向过程设计中的static 1、静态全局变量 在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下:
代码如下: //Example 1 #include &iostream.h& void fn();
//定义静态全局变量 void main() { n = 20; cout&& n && fn(); } void fn() { n++; cout&& n && }
静态全局变量有以下特点: 该变量在全局数据区分配内存; 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化); 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;  静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的 代码区,全局数据区,堆区,栈区 一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将
//定义静态全局变量 改为
//定义全局变量 程序照样正常运行。 的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处: 静态全局变量不能被其它文件所用; 其它文件中可以定义相同名字的变量,不会发生冲突; 您可以将上述示例代码改为如下:
代码如下: //Example 2 //File1 #include &iostream.h& void fn();
//定义静态全局变量 void main() { n=20; cout&&n&& fn(); } //File2 #include &iostream.h&
void fn() { n++; cout&&n&& }
编译并运行Example 2,您就会发现上述代码可以分别通过编译,但运行时出现错误。 试着将
//定义静态全局变量 改为
//定义全局变量 再次编译运行程序,细心体会全局变量和静态全局变量的区别(验证共享和保护关系)。 2、静态局部变量 在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。 我们先举一个静态局部变量的例子,如下:
代码如下: //Example 3 #include &iostream.h& void fn(); void main() { fn(); fn(); fn(); } void fn() { static n=10; cout&&n&& n++; }
通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。 但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。 静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。 静态局部变量有以下特点: 该变量在全局数据区分配内存; 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化; 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0; 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束; 3、静态函数 在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。 静态函数的例子:
代码如下: //Example 4 #include &iostream.h& static void fn();//声明静态函数 void main() { fn(); } void fn()//定义静态函数 { int n=10; cout&&n&& }
定义静态函数的好处: 静态函数不能被其它文件所用; 其它文件中可以定义相同名字的函数,不会发生冲突;
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
12345678910c语言中static用法总结
查看: 29362|
摘要: C语言程序可以看成由一系列外部对象构成,这些外部对象可能是变量或函数。而内部变量是指定义在函数内部的函数参数及变量。外部变量定义在函数之外,因此可以在许多函数中使用。由于C语言不允许在一个函数中定义其它 ...
一、c程序存储空间布局
C程序一直由下列部分组成:
正文段——CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;
初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这里。
非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。
栈——增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。
堆——动态存储分。
|-----------|
|&&&&&&&&&& |
|-----------|
|&&&&栈&&& |&
|-----------|
|&&&&|&&&&& |
|&&&\|/&&& |
|&&&&&&&&&& |
|&&&&&&&&&& |
|&&&/|\&&& |
|&&&&|&&&&& |
|-----------|
|&&&&堆&&& |
|-----------|
|&未初始化|
|-----------|
| 初始化 |
|-----------|
| 正文段 |
|-----------|
二、&面向过程程序设计中的static
1.&全局静态变量
在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。
内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)
初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)
作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。
看下面关于作用域的程序:
//teststatic1.c
void display();
int main()
printf("%d\n",n);
display();
//teststatic2.c
//定义全局静态变量,自动初始化为0,仅在本文件中可见
void display()
printf("%d\n",n);
文件分别编译通过,但link的时候teststatic1.c中的变量n找不到定义,产生错误。
定义全局静态变量的好处:
&1&不会被其他文件所访问,修改
&2&其他文件中可以使用相同名字的变量,不会发生冲突。
2.&局部静态变量
在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。
内存中的位置:静态存储区
初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)
作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区。但是局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问。
&&&&&&当static用来修饰全局变量的时候,它就改变了全局变量的作用域(在声明他的文件之外是不可见的),但是没有改变它的存放位置,还是在静态存储区中。
3.&静态函数
&&在函数的返回类型前加上关键字static,函数就被定义成为静态函数。
&&函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。
//teststatic1.c
void display();
static void staticdis();
int main()
display();
staticdis();
renturn 0;
//teststatic2.c
void display()
staticdis();
printf("display() has been called \n");
static void staticdis()
printf("staticDis() has been called\n");
文件分别编译通过,但是连接的时候找不到函数staticdis()的定义,产生错误。
定义静态函数的好处:
&1&&其他文件中可以定义相同名字的函数,不会发生冲突
&2&&静态函数不能被其他文件所用。
存储说明符auto,register,extern,static,对应两种存储期:自动存储期和静态存储期。
auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。
关键字extern和static用来说明具有静态存储期的变量和函数。用static声明的局部变量具有静态存储持续期(static&storage&duration),或静态范围(static&extent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。
由于static变量的以上特性,可实现一些特定功能。
1.&统计次数功能
声明函数的一个局部变量,并设为static类型,作为一个计数器,这样函数每次被调用的时候就可以进行计数。这是统计函数被调用次数的最好的办法,因为这个变量是和函数息息相关的,而函数可能在多个不同的地方被调用,所以从调用者的角度来统计比较困难。代码如下:
void count();
int main()
for (i = 1; i &= 3; i++)
void count()
static num = 0;
printf(" I have been called %d",num,"times\n");
输出结果为:
I&have&been&called&1&times.
C语言程序可以看成由一系列外部对象构成,这些外部对象可能是变量或函数。而内部变量是指定义在函数内部的函数参数及变量。外部变量定义在函数之外,因此可以在许多函数中使用。由于C语言不允许在一个函数中定义其它函数,因此函数本身只能是“外部的”。
&&&&&&由于C语言代码是以文件为单位来组织的,在一个源程序所有源文件中,一个外部变量或函数只能在某个文件中定义一次,而其它文件可以通过extern声明来访问它(定义外部变量或函数的源文件中也可以包含对该外部变量的extern声明)。
&&&&&&而static则可以限定变量或函数为静态存储。如果用static限定外部变量与函数,则可以将该对象的作用域限定为被编译源文件的剩余部分。通过static限定外部对象,可以达到隐藏外部对象的目的。因而,static限定的变量或函数不会和同一程序中其它文件中同名的相冲突。如果用static限定内部变量,则该变量从程序一开始就拥有内存,不会随其所在函数的调用和退出而分配和消失。
C语言中使用静态函数的好处:
静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。
关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。
使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
c语言中static的语义
1.static变量:
a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。
b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
2.static函数(也叫内部函数)
只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)
&&&&static在c里面可以用来修饰变量,也可以用来修饰函数。
&&&&&&&& 先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含对,不要弄混。
int c* = (int *)malloc(sizeof(int));
a是全局变量,b是栈变量,c是堆变量。
&&&&&&& static对全局变量的修饰,可以认为是限制了只能是本文件引用此变量。有的程序是由好多.c文件构成。彼此可以互相引用变量,但加入static修饰之后,只能被本文件中函数引用此变量。
&&&&&&& static对栈变量的修饰,可以认为栈变量的生命周期延长到程序执行结束时。一般来说,栈变量的生命周期由OS管理,在退栈的过程中,栈变量的生命也就结束了。但加入static修饰之后,变量已经不在存储在栈中,而是和全局变量一起存储。同时,离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。
&&&&&& static对函数的修饰与对全局变量的修饰相似,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。
&& && static 声明的变量在C语言中有两方面的特征:
1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。
问题:Static的理解
关于static变量,请选择下面所有说法正确的内容:
A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
D、静态全局变量过大,可那会导致堆栈溢出。
答案与分析:
对于A,B:根据本篇概述部分的说明b),我们知道,A,B都是正确的。
对于C:根据本篇概述部分的说明a),我们知道,C是正确的(所谓的函数重入问题,下面会详细阐述)。
对于D:静态变量放在程序的全局数据区,而不是在堆栈中分配,所以不可能导致堆栈溢出,D是错误的。
因此,答案是A、B、C。
问题:不可重入函数
曾经设计过如下一个函数,在代码检视的时候被提醒有bug,因为这个函数是不可重入的,为什么?
unsigned int sum_int( unsigned int base )
static unsigned int sum = 0; // 注意,是static类型的。
for (index = 1; index &= index++)
答案与分析:
所谓的函数是可重入的(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。
这个函数之所以是不可预测的,就是因为函数中使用了static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的的函数。因此如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不用。
将上面的函数修改为可重入的函数很简单,只要将声明sum变量中的static关键字去掉,变量sum即变为一个auto 类型的变量,函数即变为一个可重入的函数。
当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
部分带宽支持: |

我要回帖

更多关于 c static 初始化 的文章

 

随机推荐