转载自C/C++中static的用法全局变量与局部变量

1.什么是static?

  static 是C/C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。

1.1static的引入

  我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不只受此函数控制)。static关键字则可以很好的解决这个问题。

另外,在C++中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。

1.2静态数据的存储

  全局(静态)存储区:分为DATA段和BSS段。DATA段(全局初始化区)存放初始化的全局变量和静态变量;BSS段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BSS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

在C++中static的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
       这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。
      静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
      static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。
优势:可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。

2.在C/C++中static的作用

2.1总的来说:

(1)生命周期:在修饰变量的时候,static修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放,但不改变作用域。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用static修饰。
(2)可见性:static修饰全局变量或函数时,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。这个函数也只能在本文件中调用,不能被其他文件调用。
(3)存储方式:Static修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为0。
(4)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用static)。

2.2静态变量与普通变量

静态全局变量有以下特点:
(1)静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量;
(2)未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为0);
(3)静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的。
优点:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突。

(4)全局变量和全局静态变量的区别

1)全局变量是不显式用static修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。
2)全局静态变量是显式用static修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用extern声明也不能使用。

2.3静态局部变量有以下特点:

(1)该变量在全局数据区分配内存;
(2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
(3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
(4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。
//example:
#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main()
{static int m1 = 2, m2;int i = 1;char*p;char str[10] = "hello";char*q = "hello";p = (char *)malloc(100);free(p);printf("栈区-变量地址    i:%p\n", &i);printf("栈区-变量地址   p:%p\n", &p);printf("栈区-变量地址 str:%p\n", str);printf("栈区-变量地址   q:%p\n", &q);printf("堆区地址-动态申请:%p\n", p);printf("全局外部有初值 k1:%p\n", &k1);printf("   外部无初值 k2:%p\n", &k2);printf("静态外部有初值 k3:%p\n", &k3);printf("   外静无初值 k4:%p\n", &k4);printf("  内静态有初值 m1:%p\n", &m1);printf("  内静态无初值 m2:%p\n", &m2);printf("    文字常量地址:%p, %s\n", q, q);printf("      程序区地址:%p\n", &main);return 0;
}

3.1特别的,在C++中:

static关键字最基本的用法是:

1、被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来

2、被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来

被static修饰的变量、被static修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。

  在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

静态成员的定义或声明要加个关键static。静态成员可以通过双冒号来使用即<类名>::<静态成员名>。

3.2静态类相关

//example1:通过类名调用静态成员函数和非静态成员函数class Point{public:void init(){}static void output(){}};void main(){Point::init();Point::output();}

报错: 'Point::init' : illegal call of non-static member function

结论1:不能通过类名来调用类的非静态成员函数。

//example2:通过类的对象调用静态成员函数和非静态成员函数class Point{public:void init(){}static void output(){}};
void main()
{Point pt;pt.init();pt.output();
}

编译通过。

结论2:类的对象可以使用静态成员函数和非静态成员函数。

//example3:在类的静态成员函数中使用类的非静态成员
#include <stdio.h>
class Point
{public:void init(){}static void output(){printf("%d\n", m_x);}
private:int m_x;
};
void main()
{Point pt;pt.output();
}

编译出错:error C2597: illegal reference to data member 'Point::m_x' in a static member function

  因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

结论3:静态成员函数中不能引用非静态成员。

//example4:在类的非静态成员函数中使用类的静态成员
class Point
{public:void init(){output();}static void output(){}
};
void main()
{Point pt;  Pt.init();pt.output();
}

编译通过。

结论4:类的非静态成员函数可以调用用静态成员函数,但反之不能。

//example5:使用类的静态成员变量#include <stdio.h>class Point{public:Point(){m_nPointCount++;}~Point(){m_nPointCount--;}static void output(){printf("%d\n", m_nPointCount);}private:static int m_nPointCount;};void main(){Point pt;pt.output();}

按Ctrl+F7编译无错误,按F7生成EXE程序时报链接错误

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

这是因为类的静态成员变量在使用前必须先初始化。

在main()函数前加上int Point::m_nPointCount = 0;

再编译链接无错误,运行程序将输出1。

结论5:类的静态成员变量必须先初始化再使用。

  思考总结:静态资源属于类,但是是独立于类存在的。从J类的加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类实例化对象的时候加载的。 类的初始化早于类实例化对象,比如Class.forName(“xxx”)方法,就是初始化了一个类,但是并没有实例化对象,只是加载这个类的静态资源罢 了。所以对于静态资源来说,它是不可能知道一个类中有哪些非静态资源的;但是对于非静态资源来说就不一样了,由于它是实例化对象出来之后产生的,因此属于类的这些东西它都能认识。所以上面的几个问题答案就很明确了:

1)静态方法能不能引用非静态资源?不能,实例化对象的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。

2)静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。

3)非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是实例化对象之后才产生的,那么属于类的内容它都认识。

  (static修饰类:这个用得相对比前面的用法少多了,static一般情况下来说是不可以修饰类的, 如果static要修饰一个类,说明这个类是一个静态内部类(注意static只能修饰一个内部类),也就是匿名内部类。像线程池 ThreadPoolExecutor中的四种拒绝机制CallerRunsPolicy、AbortPolicy、DiscardPolicy、 DiscardOldestPolicy就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。)

3.3总结:

(1)静态成员函数中不能调用非静态成员。

(2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。

(3)静态成员变量使用前必须先初始化(如int MyClass::m_nNumber = 0;),否则会在linker时出错。

参考:http://blog.csdn.net/morewindows/article/details/6721430

一般总结:在类中,static可以用来修饰静态数据成员和静态成员方法
静态数据成员
(1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
(2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
(3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为0
(4)静态数据成员既可以通过对象名引用,也可以通过类名引用。

静态成员函数
(1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
(2)非静态成员函数有this指针,而静态成员函数没有this指针。
(3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

C/C++中static的用法全局变量与局部变量相关推荐

  1. 【C++】C/C++ 中 static 的用法全局变量与局部变量

    C/C++ 中 static 的用法全局变量与局部变量 目录 1. 什么是static? 1.1 static 的引入 1.2 静态数据的存储 2. 在 C/C++ 中static的作用 2.1 总的 ...

  2. C和C++中static的用法及友元

    C和C++中static的用法 文章目录 C和C++中static的用法 一.**C语言中**: 二.**C++中**: 三.**友元**: 一.C语言中: static 修饰全局变量表示该变量只在本 ...

  3. java中static的用法_Java类中static的用法

    关于Java中static的使用有以下四种情况: 1.静态成员变量        被static修饰的成员变量,叫静态成员变量或类变量:没有被static修饰的变量,叫实例变量. 两者的区别是: 静态 ...

  4. iOS中 static变量与全局、局部变量的区别 !

    static变量与全局.局部变量的区别 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式. 这两者在存储方式上并 ...

  5. c++中static的用法详解

    C 语言的 static 关键字有三种(具体来说是两种)用途: 1. 静态局部变量:用于函数体内部修饰变量,这种变量的生存期长于该函数. 下面展示一些 内联代码片. int foo(){static ...

  6. C/C++中static关键字用法汇总

    1. 函数内static局部变量:变量在程序初始化时被分配,直到程序退出前才被释放,也就是static是按照程序的生命周期来分配释放变量的,而不是变量自己的生命周期.多次调用,仅需一次初始化. 2. ...

  7. C++中static关键字用法

    原文参考:https://zhuanlan.zhihu.com/p/347930016 1.面向过程设计中的static 1.1静态全局变量 在全局变量前,加上关键字static,该变量就被定义成为一 ...

  8. java中static的用法

    static变量有点类似于C中的全局变量的概念.值得探讨的是静态变量的初始化问题.拿以下程序为例 class Value{ static int c=0; Value(){ c=15; } Value ...

  9. Java中static final用法小结

    一.final 根据程序上下文环境,Java关键字final有"这是无法改变的"或者"终态的"含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可能出于两种理 ...

最新文章

  1. 批处理编程的异类——时钟(Clock)
  2. java定义一个学生类cstudent_编写一个JAVA程序片断 定义一个表示学生的类student
  3. 笔记本电脑没有鼠标怎么右键_联想笔记本电脑没有声音怎么修复
  4. C#刷剑指Offer | 【常考题】最小的k个数
  5. C链表反转(时间复杂度O(n))
  6. h3c服务器r690修改启动顺序,H3C UIS R690 G2服务器 CPU快速入门-6W101
  7. 【例5.2】组合的输出
  8. 在线JSON转flow工具
  9. properties加载的几种方式
  10. 基础之 window-self-top-opener
  11. Android Spinner 设置setOnItemSelectedListener时,竟会默认触发一次事件!
  12. 上海城市坐标系转换的空间校正方法(附控制点文件)
  13. 计算机网络的性能指标
  14. WinHex自定义模板
  15. 用JMS578转接板开卡PS3111主控pSLC模式,带固件下载
  16. 三个非负整数 马蹄集
  17. 整型最大值java,整数的最大值
  18. 蒟蒻打CF#729div 2
  19. php 固定表头,PHPExcel如何冻结(锁定)表头
  20. [UER#6 C]逃跑

热门文章

  1. java 读取图片给 matlab_如何将MATLAB图像处理程序转换为java?
  2. python中list index out of range_Python知识精解:str split()方法
  3. python 跳一跳辅助_微信跳一跳辅助自动跳Python
  4. 详解Bootstrap glyphicons-halflings-regular.woff2 Not found
  5. [你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器
  6. Java 并发基础——线程安全性
  7. 一步步编写操作系统 45 用c语言编写内核2
  8. 老王说ros的tf库
  9. python语言中百分号是什么意思_Python中%是什么意思?python中百分号如何使用?...
  10. 【Python CheckiO 题解】Second Index