C,C++中的static
在C和C++中,static都有两种基本的含义,并且这两种含义经常是互相有冲突的:
1) 在固定的地址上分配,也就是说对象是在一个特殊的静态数据区上创建的,而不是每次
函数调用时在堆栈上产生的。这也是静态存储的概念。
2) 对一个特定的编译单位来说是本地的(就像我们在后面将要看到的,这在C++中包括类
的范围)。这里static控制名字的可见性,所以这个名字在这个单元或类之外是不可见的。这也
描述了连接的概念,它决定连接器将看到哪些名字。
1.函数内部的静态变量
通常,在函数体内定义一个变量时,编译器使得每次函数调用时堆栈的指针向下移一个适
当的位置,为这些内部变量分配内存。如果这个变量有一个初始化表达式,那么每当程序运行
到此处,初始化就被执行。
然而,有时想在两次函数调用之间保留一个变量的值,我们可以通过定义一个全局变量来
实现这点,但这样一来,这个变量就不仅仅受这个函数的控制。C和C++都允许在函数内部创
建一个static对象,这个对象将存储在程序的静态数据区中,而不是在堆栈中。这个对象只在
函数第一次调用时初始化一次,以后它将在两次函数之间保持它的值。
如果没有为一个预定义类型的静态变量提供一个初始值的话,编译器会确保在程序开始时为它初始化为0(将转化为适当的类型)。
2.函数体内部的静态对象
用户自定义的静态变量同一般的静态对象的规则是一样的,而且它同样也必须有初始化操作。
但是,零赋值只对预定义类型有效,用户自定义类型必须用构造函数来初始化。因此,如果我们
在定义一个静态对象时没有指定构造函数参数,这个类就必须有缺省的构造函数。
tips:
在C++中,全局静态对象的构造函数是在main()之前调用的,所以我们现在有了一个在进
入main()之前执行一段代码的简单的、可移植的方法,并且可以在退出main()之后用析构函数
执行代码。在C中要做到这一点,我们不得不熟悉编译器开发商的汇编语言的开始代码。
3.控制连接
一般情况下,在文件范围内的所有名字(既不嵌套在类或函数中的名字)对程序中的所有
编译单元来说都是可见的。这就是所谓的外部连接,因为在连接时这个名字对连接器来说是可
见的,外部的编译单元、全局变量和普通函数都有外部连接。
有时我们可能想限制一个名字的可见性。想让一个变量在文件范围内是可见的,这样这个
文件中的所有函数都可以使用它,但不想让这个文件之外的函数看到或访问该变量,或不想这
个变量的名字与外部的标识符相冲突。
在文件范围内,一个被明确声明为static的对象或函数的名字对编译单元(一个.cpp文件)来说是局部变量;这些名字有内部连接。这意味着我们可以在其他的编译单元中使用同样的名字,而不会发生名字冲突。
内部连接的一个好处是这个名字可以放在一个头文件中而不用担心连接时发生冲突。那些
通常放在头文件里的名字,像常量、内联函数( inline function),在缺省情况下都是内部连接
的(当然常量只有在C + +中缺省情况下是内部连接的,在C中它缺省为外部连接)。注意连接只
引用那些在连接/装载期间有地址的成员,因此类声明和局部变量并没有连接。
• 冲突问题
下面例子说明了static的两个含义怎样彼此交叉的。所有的全局对象都是隐含为静态存储类,
所以如果我们定义(在文件范围)
int a=0;
则a被存储在程序的静态数据区,在进入main()函数之前,a即已初始化了。另外,a对全局都是可
见的,包括所有的编译单元。用可见性术语,s t a t i c(只在编译单元内可见)的反义是e x t e r n,它
表示这个名字对所有的编译单元都是可见的。所以上面的定义和下面的定义是相同的。
extern int a=0;
但如果这样定义:
static int a=0;
我们只不过改变了a的可见性,现在a成了一个内部连接。但存储类型没有改变—对象总是驻
留在静态数据区,而不管是s t a t i c还是e x t e r n。
一旦进入局部变量,s t a t i c就不会再改变变量的可见性(这时e x t e r n是没有意义的),而只
是改变变量的存储类型。
对函数名,s t a t i c和e x t e r n只会改变它的可见性,所以如果说:
extern void f();
它和没有修饰时的声明是一样的:
void f();
如果定义:
static void f();
它意味着f ( )只在本编译单元内是可见的,这有时称作文件静态。
4.其他的存储类型指定符
我们会看到s t a t i c和e x t e r n用得很普遍。另外还有两个存储类型指定符,这两种用得较少。
一个是a u t o ,人们几乎不用它,因为它告诉编译器这是一个局部变量,实际上编译器总是可以从
变量定义时的上下文中判断出这是一个局部变量。所以a u t o是多余的。还有一个是r e g i s t e r,它
也是局部变量,但它告诉编译器这个特殊的变量要经常用到,所以编译器应该尽可能地让它保
存在寄存器中。它用于优化代码。各种编译器对这种类型的变量处理方式也不尽相同,它们有
时会忽略这种存储类型的指定。一般,如果要用到这个变量的地址, r e g i s t e r指定符通常都会被
忽略。应该避免用r e g i s t e r类型,因为编译器在优化代码方面通常比我们做得更好。
C,C++中的static的更多相关文章
- Android 中关于static的使用问题
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5251564.html 项目中,在不停地接收串口数据很长一段时间(几小时)后,会偶然性的报错.初步排除了oom ...
- (转)Java中的static关键字解析
转载: http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: &q ...
- 关于Java中的static关键字
Java中的 static 关键字,确实是一个关键的字(key word),今天就来总结一下它的用法,说说为什么关键. Java中的 static 关键字主要是用来做内存管理的.理解了这句话才能够比较 ...
- Java中的static关键字解析
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- C++中的static关键字的总结
C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. 1.面向过程设计中的st ...
- java中的static使用--静态变量、静态方法
Java 中的 static 使用之静态变量 大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的对象共享同一个成员.此时就是 s ...
- (转)Java中的static关键字解析
转自http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: “sta ...
- Java中的static的使用
Java中的static使用之静态变量 神话丿小王子的博客主页 1.Java 中被static修饰的成员称为静态成员或类成员.它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享.且优先于对象 ...
- java中的static详解
如果一个类成员被声明为static,它就能够在类的任何对象创建之前被访问,而不必引用任何对象.static 成员的最常见的例子是main( ) .因为在程序开始执行时必须调用main() ,所以它被声 ...
- Java 中的 static 使用之静态变量
大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的对象共享同一个成员.此时就是 static 大显身手的时候了!! Java 中 ...
随机推荐
- VC调试技巧
Visual C++ 的 C 运行时刻函数库标识模板0xCD 已经分配的数据(alloCated Data)0xDD 已经释放的数据(Deleted Data)0xFD 被保护的数据 ...
- 奔小康赚大钱 hdu 2255
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- gradle学习系列之eclipse中简单构建android项目
看不到图片能够去訪问这个网址看看:http://pan.baidu.com/s/1o6FrFkA 一.什么是Gradle 官网www.gradle.org上介绍Gradle是升级版(evolved)的 ...
- Java中double变量精确到小数点后几(2)位
import java.math.BigDecimal; import java.text.NumberFormat; public class Java中double类型的数据精确到小数点后两位 { ...
- Android中关于JNI 的学习(六)JNI中注冊方法的实现
在前面的样例中,我们会发现,当在Java类中定义一个方法的时候,例如以下: public class ParamTransferTest { public static int testval = 1 ...
- Linux创建修改删除用户和组
Linux 创建修改删除用户和组 介绍 在日常的维护过程中创建用户操作用的相对会多一些,但是在这个过程中涉及到的知识点就不单单就是useradd了,接下来就来详细了解账号管理的相关信息. 用户信息 先 ...
- poj 2166 构造
一个看了解题报告才能想明白的题目,第一点比较容易想明白,就是每次把1交换到堆顶之后如果能够换到最后面的位置那么一定是最优的,但是怎么实现这个没有想明白. 题解的那种构建方法,及从2开始插入,是可以保证 ...
- BT渗透工具使用学习笔记
BT51.信息收集2.扫描工具3.漏洞发现4.社会工程学工具5.运用层攻击MSF6.局域网攻击7.密码破解8.维持访问一.DNS信息收集1.Dnsenum/pentest/enumeration/dn ...
- Codeforces Round #246 (Div. 2) D. Prefixes and Suffixes(后缀数组orKMP)
D. Prefixes and Suffixes time limit per test 1 second memory limit per test 256 megabytes input stan ...
- Hadoop-2.4.0安装和wordcount执行验证
Hadoop-2.4.0安装和wordcount执行验证 下面描写叙述了64位centos6.5机器下,安装32位hadoop-2.4.0,并通过执行 系统自带的WordCount样例来验证服务正确性 ...