您的位置:首页 > 编程语言 > C语言/C++

C以及C++语言中static作用

2016-07-09 16:54 357 查看

文章前面部分转自 MainTao 的http://www.cnblogs.com/dc10101/archive/2007/08/22/865556.html 。文章主要是在讨论C语言下static的作用及意义。其中第二条的保持变量内容持久化,既保证了变量count的作用域可见在函数内,同时又能够保持变量变化记录持久化。

第4点总结来自http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777441.html 
关于C++类中的static 摘自http://www.cnblogs.com/gysm/archive/2011/09/16/2179277.html

static的作用

   
在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。
1、先来介绍它的第一条也是最重要的一条:隐藏。
当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。
下面是a.c的内容
char a = 'A'; // global variable
void msg() 

{

    printf("Hello\n"); 

}

 
下面是main.c的内容
int main(void)

{    

    extern char a;    // extern variable must be declared before use
    printf("%c ", a);

    (void)msg();

    return 0;

}

 
程序的运行结果是:
A Hello
你可能会问:为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。
如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。
2、static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。
#include <stdio.h>

int fun(void){

    static int count = 10;    // 事实上此赋值语句从来没有执行过,实际上只在声明时进行了初始化,后面的调用均不初始化
    return count--;

}

int count = 1;

int main(void)

{    

    printf("global\t\tlocal static\n");

    for(; count <= 10; ++count)

        printf("%d\t\t%d\n", count, fun());    

    

    return 0;

}

 
程序的运行结果是:
global          local static
1               10
2               9
3               8
4               7
5               6
6               5
7               4
8               3
9               2
10              1

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

该变量在全局数据区分配内存;

静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;

静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;

它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束
 

3、static的第三个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。不妨做个小实验验证一下。
#include <stdio.h>

int a;

int main(void)

{

    int i;

    static char str[10];

    printf("integer: %d;  string: (begin)%s(end)", a, str);

    return 0;

}

程序的运行结果如下
integer: 0; string: (begin)(end)
最后对static的三条作用做一句话总结。首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。

(转者注:以下摘自 http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777441.html ,其中的抽象分析、设计理念很值得理解,便于记忆。)

4. 用static声明的函数和变量小结

    static 声明的变量在C语言中有两方面的特征:

1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。

2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

 Tips:

A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;

B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;

C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;

D.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)

E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

    函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

扩展分析:

     术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。随后,static在C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义。最后,C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数(与Java中此关键字的含义相同)。

全局变量、静态全局变量、静态局部变量和局部变量的区别

变量可以分为:全局变量、静态全局变量、静态局部变量和局部变量。

(1) 按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存放在内存的栈区。

(2) 按作用域分,  全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。

     全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

    从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。

(1) static 函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件

(2) static全局变量与普通的全局变量有什么区别:static全局变量只初始化一次,防止在其他文件单元中被引用;

(3) static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;

(4) static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝.

(5) 全局变量和静态变量如果没有手工初始化,则由编译器初始化为0。局部变量的值不可知。

转者注:以下部分摘自 http://www.cnblogs.com/gysm/archive/2011/09/16/2179277.html  其中对static函数的访问权限由于无 this 指针而影响,值得理解。


C++类中的static数据成员,static成员函数

      C++类中谈到static,我们可以在类中定义static成员,static成员函数!C++primer里面讲过:static成员它不像普通的数据成员,static数据成员独立于该类的任意对象而存在,每个static数据成员是与类关联的对象,并不与该类的对象相关联!这句话可能比较拗口,其实可以这么理解:每个static数据成员可以看成是类的一个对象,而不与该类定义的对象有任何关系!下面我们就来具体看看类中的static数据成员!

      谈到数据成员,我们最先想到的应该是怎么去定义一个static数据成员,static数据成员是存储在程序的静态存储区,而并不是在栈空间上。既然是static数据成员,所以关键字static是必不可少的,例如:

  

1 static.h文件
2 #include  <iostream>
3 #include  <string>
4 using namespace std;
5 class Person
6 {
7 private:
8     string name;
9     static int age;
10 public:
11     Person(const string&nm):name(nm)
12     {}
13     void Print()
14     {
15         cout<<name<<" is "<<age<<endl;
16     }
17 };
18 int Person::age=20;
19
20 static.cpp文件
21
22 #include "stdafx.h"
23 #include "static.h"
24 #include <iostream>
25 using namespace std;
26
27 int _tmain(int argc, _TCHAR* argv[])
28 {
29     Person person("tom");
30     person.Print();
31     cout<<endl;
32     return 0;
33 }


Person类中定义了一个static数据成员age,注意在类中不能对static数据成员进行初始化,要初始化的话必须在类外进行定义!注意,static数据成员不是通过类构造函数进行初始化的!如上面的代码所示:在类外定义int Person::age=20;这里前面就不要再加static了。如果类中有多个static数据成员,static数据成员初始化的次序是按照static数据成员在类中的声明次序进行初始化的,初始化了之后,就可以使用static数据成员了,我们可以通过作用域操作符从类直接调用static数据成员,或者通过对象,引用,或指向该类类型对象的指针间接调用(这种情况下static数据成员必须是public的访问权限,如果定义在private访问权限下是不行的)。

     
      说完了static成员后,我们再来看看static成员函数,static成员是类的组成部分并不是任何对象的组成部分,因此,static成员函数没有this指针。我们知道,一般而言,类中的成员函数具有一个附加的隐含实参,即指向该类对象的一个指针。这个隐含实参命名为this。因为static成员函数不是任何对象的组成部分,所以static成员函数就没有this形参了,无法访问属于类对象的非静态数据成员和非静态成员函数。

有技术才有魅力,在飘雪的季节守候花开!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ static