C语言中static--作用

来源:互联网 发布:淘宝网地板胶 编辑:程序博客网 时间:2024/06/06 04:02

在C语言中static的作用如下


版本一

  • 隐藏:
    • a.c中的普通全局变量普通函数,在b.c中可见、可声明、可引用。
    • a.c中的静态全局变量静态函数,在b.c中不可见、不可声明、不可引用。
//a.c#include <stdio.h>char a = 'A';//普通全局函数void fun()//普通全局函数{    printf("hello world\n");}
//b.c#include <stdio.h>extern void fun();//声明外部函数为全局函数int main(void){    extern char a;//声明外部变量为局部变量    printf("%c\n",a);    fun();    return 0;}

编译:gcc *.c (gcc a.c b.c)
输出:
A
hello world

//a.c#include <stdio.h>static char a = 'A';//静态全局变量,对外文件隐藏static void fun()//静态全局函数,对外文件隐藏{    printf("hello world\n");}

编译:gcc *.c
编译报错:
/tmp/ccp9gtxS.o:在函数‘main’中:
b.c:(.text+0x14):对‘a’未定义的引用
b.c:(.text+0x2d):对‘fun’未定义的引用
collect2: error: ld returned 1 exit status

  • 保持变量内容持久:
    • 存储在静态存储区的变量会在程序刚运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量、static静态变量,只不过和全局变量比起来,static可以控制变量的可见范围,也就是static变量兼具全局变量的功能,另外还多一个,可以隐藏。
  • 把普通局部变量改变(这么说其实并不严谨)为静态局部变量后,改变了原先的存储方式(改变了生命期)
  • 把普通全局变量改变为静态全局变量后,改变了原先的作用域(限制了使用范围,对外文件因隐藏)
  • 默认初始化为0:
    • 普通全局变量也具有这个属性,因为普通全局变量也存储在静态数据区
    • 在静态数据区,内存中所有的字节默认值是0x00,某些时候这一特性可以减少程序员的工作量。比如初始化一个稀疏矩阵。再比如要把一个字符数组当字符串来用,但是又觉得每次在字符数组末尾加’\0’麻烦,就可以把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。
  • c++类中static成员声明:
    • 在类中声明 static变量、static函数时,初始化时使用作用域运算符::来表明它所属的类,因此静态成员是类的成员不是对象的成员。
      • 类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。
      • 不能将静态成员函数定义为虚函数。不能将静态成员函数放入虚表中。
      • 因为静态成员声明于类中,操作于类外,所以对其取址操作就有些特殊,静态变量地址是指向其数据类型的指针,静态函数地址类型是一个nonmember函数指针。
      • 由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X W indow系统结合,同时也成功的应用于线程函数身上。
      • static并没有增加程序的时空开销,相反它还缩短了子类对父类静态成员的访问,节省了子类的内存空间。
      • 静态数据成员是静态存储的,所以(c++)必须对它进行初始化,否则编译不会报错,链接时会报错。
      • 静态成员初始化与一般数据成员初始化不同:
        • 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象混淆。
        • 初始化时不加该成员的访问权限控制符private、protected、public。
        • 初始化时使用作用域运算符::来标明它所属的类:
          • <数据类型><类名>::<静态数据成员名>=值;
      • 为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们又重新定义了静态成员,这不会引起错误。编译器采用了一种巧妙的手法:name-mangling用以生成唯一的标识。
DBHelper * DBHelper::instance = NULL;DBHelper * DbHelper::getInstance(){    if(instance == NULL)    {        instance = DBHelper();    }    return instance;} 

版本二

  • 限制作用域:修饰函数、全局变量(文件级的事物)起到限制作用域的作用,只能在本文件中访问,即使在另一个文件中用extern声明也不可以(改变链接属性),反过来说,如果不用static修饰,那么其他文件可以extern声明并使用这个全局变量(其实包含其他文件的头文件就可以)。
  • 延长生命周期:修饰局部变量(函数级的事物)时,延长局部变量的生命周期(或者保持局部变量内容持久)
  • 默认初始化:修饰的变量初始化为缺省值0(类似于全局变量的默认初始化),static修饰的局部变量存放在全局数据区的静态变量区,所以初始化时自动初始化为0.

版本三

  • 第一、在修饰变量的时候,static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
  • 第二、static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。
  • 第三、static修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0;
    • 不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用static修饰
    • 考虑到数据安全性(当程想要使用全局变量的时候应该先考虑使用static)

在C++中static关键字的作用除了C中的还有


在类中,static可以用来修饰静态数据成员和静态成员方法

  • 静态数据成员
    • 静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
    • 静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
    • 静态数据成员可以被初始化,但是只能在类体外进行初始化,若为对静态数据成员赋初值,则编译器会自动为其初始化为0
    • 静态数据成员既可以通过对象名引用,也可以通过类名引用。
  • 静态成员函数
    • 静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
    • 非静态成员函数有this指针,而静态成员函数没有this指针。
    • 静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

补充


C语言中普通全局变量编译器会给个缺省值

#include <stdio.h>int num;//缺省值0double dnum;char ch;int main(void){    printf("%d\n",num);//0    printf("%lf\n",dnum);//0.000000    printf("%d\n",ch);//0    int num2;    double dnum2;    char ch2;    printf("%d\n",num2);//-1077784524    printf("%lf\n",dnum2);//0.000000    printf("%d\n",ch2);//0    return 0;}
原创粉丝点击