首页 > 编程 > C++ > 正文

c++中的static和extern

2019-11-06 08:10:55
字体:
来源:转载
供稿:网友

一、static本质作用

与static相对的关键字是auto,两者是一对。我们一般声明变量,如:int a,其实都是auto int a,只是auto省略了而已,但是static不能省略。要理解static,最好先理解auto。auto的含义是由程序自动控制变量的生存周期,通常是变量在进入其作用域的时候被分配,离开其作用域的时候被释放;而static则不同,变量在程序初始化时被分配,直到程序退出前才被释放;也就是static是按照程序的生命周期来分配释放变量的,而不是按照变量自己的生命周期。

二、static用法

1.局部变量

如:

void func()  {  int a;  static int b;  }

 就算函数结束了,b的值也能够一直保持。每一次调用该函数,变量a都是新的,因为它是在进入函数体的时候被分配,退出函数体的时候被释放,所以多个线程调用该函数,都会拥有各自独立的变量a,因为它总是要被重新分配的;而变量b不管你是否使用该函数,在程序初始化时就被分配的了,或者在第一次执行到它的声明的时候分配(不同的编译器可能不同),所以多个线程调用该函数的时候,总是访问同一个变量b,这也是在多线程编程中必须注意的!

一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束。但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅限于该语句块。

2.类的静态数据成员

class A

    PRivate:

static int s_value;

};

   类的静态成员必须初始化才能使用,道因为它是在程序初始化的时候分配的,所以必须有初始化,类中只是声明,在cpp中才是初始化,静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:

 int A::s_value = 0;//<数据类型><类名>::<静态数据成员名>=<值>,注意,这里没有static的修饰!

   使用静态成员时,可以通过双冒号(即<类名>::<静态成员名>)。

   类的静态成员是该类所有实例的共用成员,也就是在该类的范畴内是个全局变量,也可以理解为是一个名为A::s_value的全局变量,只不过它是带有类安全属性的。道理很简单,因为它是在程序初始化的时候分配的,所以只分配一次,所以就是共用的。

3.类的静态成员函数

class A 

 { 

    private:

void init();

static void output();

};

void main()    {A::init();A::output();    }//A::init();会出错,因为不能通过类名来调用类的非静态成员函数。

void main()    {A pt;pt.init();pt.output();    }//编译通过,因为类的对象可以使用静态成员函数和非静态成员函数。

  静态成员函数和静态数据成员一样,它们都属于类的静态成员,不是对象成员。因此,对静态成员的引用不需要用对象名,当然,通过对象来使用也可以。在静态成员函数的实现中不能直接引用类的非静态成员,可以引用类中的静态成员。如果静态成员函数中要引用非静态成员时,可通过对象来引用。因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以调用就会出错,就好比没有声明一个变量却提前使用它一样。

实现的时候也不需要static的修饰,因为static是声明性关键字;类的静态函数是在该类的范畴内的全局函数,实际上,它就是增加了类的访问权限的全局函数:void A::output();

注意:静态成员函数可以继承和覆盖,但无法是虚函数;在类的非静态成员函数中可以使用类的静态成员。

4.文件内全局变量

若在cpp中有,static int g_value = 0;

这个变量的含义是在该cpp内有效,其他的cpp文件不能访问这个变量;如果有两个cpp文件声明了同名的全局静态变量,那么他们实际上是独立的两个变量;如果不使用static声明全局变量:int g_value = 0;那么将无法保证这个变量不被别的cpp共享,也无法保证一定能被别的cpp共享。

如果在一个h文件中声明:static int g_vaule = 0;

那么会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的;所以也不建议这样的写法,因为只是创建了一组同名而不同作用域的变量;

在cpp内声明: static void func();

函数的实现不需要static修饰,那么这个函数只可在本cpp内使用,不会同其他cpp中的同名函数引起冲突;不要在头文件中声明static的全局函数,不要在cpp内声明非static的全局函数,如果你要在多个cpp中复用该函数,就把它的声明提到头文件里去,否则在cpp内部声明需要加上static修饰;在C语言中这点尤为重要!

三、extern

   在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。在这里要注意extern声明的位置对其作用域也有关系,如果是在main函数中进行声明的,则只能在main函数中调用,在其它函数中不能调用。其实要调用其它文件中的函数和变量,只需把该文件用#include包含进来即可,为啥要用extern?因为用extern会加速程序的编译过程,这样能节省时间。

1.h文件中

在头文件里声明为extern的:extern int g_value; // 注意,不要初始化值!

然后在其中任何一个包含该头文件的cpp中初始化(一次)就好:

int g_value = 0; // 初始化一样不要extern修饰,因为extern也是声明性关键字;

然后所有包含该头文件的cpp文件都可以用g_value这个名字访问相同的一个变量。

2.cpp文件中

file1.c int a=1;  file2.c  #include<stdio.h> extern int a;  int main(void)  {  printf("%d/",a);  return 0;  } 这样,file2就可以用file1中的int a了,但是如果在file1中把int a=1改为static int a=1;那么在file2.c是无法访问到变量a的。原因在于用static对全局变量进行修饰改变了其作用域的范围,由原来的整个工程可见变为本源文件可见。

3.指示调用规范

在C++中extern还有另外一种作用,用于指示C或者C++函数的调用规范。比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同,用此来解决名字匹配的问题。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选