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 中 ...
随机推荐
- D2010 RTTI + Attribute 简单实现ORM
还记得David I 今年四月来盛大时,被问及“反射机制能再做得好一点吗?我们想放弃RTTI”,David I 回答“这的确是需要考虑的地方,当然RTTI我们不会放弃的”.(这个白胡子的老哥哥还真很可 ...
- ThinkPhp学习02
原文:ThinkPhp学习02 一.什么是MVC M -Model 编写model类 对数据进行操作 V -View 编写html文件,页面呈现 C -Controll ...
- haproxy 看到的是https,后台是http的原因
https://www.zjtest6.com/admin/api/menu haproxy 日志: Jun 24 13:23:02 localhost haproxy[23205]: 192.168 ...
- codeforces.com/contest/325/problem/B
http://codeforces.com/contest/325/problem/B B. Stadium and Games time limit per test 1 second memory ...
- Zero Clipboard - 跨浏览器兼容的“复制到剪贴板”功能
开发中经常会用到复制的功能,在 IE 下实现比较简单,但要想做到跨浏览器比较困难了. 本文将介绍一个跨浏览器的库类 Zero Clipboard ,它利用 Flash 进行复制,所以只要浏览器装有 F ...
- 扯谈网络编程之自己实现ping
ping是基于ICMP(Internet Control Message Protocol)协议实现的.而ICMP协议是在IP层实现的. ping实际上是发起者发送一个Echo Request(typ ...
- 第 3 章 编写 PAM 应用程序和服务
Solaris 开发者安全性指南 Previous: 第 2 章 开发特权应用程序 Next: 第 4 章 编写使用 GSS-API 的应用程序 第 3 章 编写 PAM 应用程序和服务 可插拔验证模 ...
- Spring中继承配置的注入方法
(1)两个java类.一个父类一个字类 package com.lc.inherit; /* * 这里是父类 */ public class Student { protected String na ...
- Android开发之模板模式初探
模板模式我认为在Android的开发中是最长用到的,基本是随处可见的,认识该模式,有助于我们对Android的源代码及框架有一个更深层次的认识.那什么是模板模式呢,模板模式就是定义一个基本框架,将当中 ...
- Appium介绍
Appium介绍 Appium是一个移动端的自动化框架,可用于测试原生应用,移动网页应用和混合型应用,且是跨平台的.可用于IOS和Android以及firefox的操作系统.原生的应用是指用andro ...