static 和 extern ====================== 静态全局变量 --------------------------- 在全局变量前,加上关键字 static,该变量就被定义成为一个静态全局变量。 特点: - 该变量在 **全局数据区** 分配内存; - 未经初始化的静态全局变量会被程序自动初始化为 0;(自动变量的值是随机的,除非它被显式初始化) - 静态全局变量在声明它的整个文件都是可见的,而在 **文件之外是不可见的** ,其它文件中可以定义相同名字的变量,不会发生冲突。  静态函数 ------------------------- 在函数的返回类型前加上 static 关键字,函数即被定义为静态函数。 静态函数与普通函数不同,它 **只能在声明它的文件当中可见** ,不能被其它文件使用。 其它文件中可以定义相同名字的函数,不会发生冲突,这点与静态全局变量相似。 .. note:: 如果在头文件中定义 static 全局变量/函数,在已经 include 该头文件的源文件中是可以直接使用这个 static 全局变量/函数(相当于头文件的内容在当前文件中展开)。 `Static variables are local to the compilation unit `_ . A compilation unit is basically a ``.cpp`` file with the contents of the ``.h`` file inserted in place of each ``#include`` directive. 多个源文件 include 该头文件也可以编译通过,相当于各个源文件中都定义了只在各自文件内可见的 static 全局变量/函数。 静态局部变量 -------------------------- 在局部变量前,加上关键字 static,该变量就被定义成为一个静态局部变量。 特点: - 该变量在全局数据区分配内存; - 静态局部变量在程序执行到该对象的声明处时被首次初始化,即 **以后的函数调用不再进行初始化** ; - 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0; - 它始终驻留在全局数据区,其生命周期一直持续到整个程序执行结束。但其作用域仍为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。 .. code-block:: cpp :linenos: void func() { static int a = 1; // 初次调用func()时才会执行初始化 cout << a << endl; a ++; } int main() { func(); // 1 func(); // 2 return 0; } 静态成员变量 -------------------------- 在类内数据成员的声明前加上关键字 static,该数据成员就是类内的静态数据成员。 特点: - 对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。在没有产生类的实例时,我们就可以操作它。 - 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。 - 静态数据成员和普通数据成员一样遵从 public/protected/private 访问规则。 - (类定义体外部)静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为: ``<数据类型> <类名>::<静态数据成员名> = <值>`` - 类的静态数据成员有两种访问形式: ``<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>`` 静态成员函数 -------------------------- 普通的成员函数一般都隐含了一个 ``this`` 指针, ``this`` 指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。 通常情况下, ``this`` 是缺省的,如函数 ``fn()`` 实际上是 ``this->fn()`` 。 但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它 **不具有this指针** 。 从这个意义上讲,它 **无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数** 。 非静态成员函数可以任意地访问静态成员函数和静态数据成员。 .. code-block:: cpp :linenos: class Myclass { private: int a, b, c; static int sum; //声明静态数据成员 public: Myclass(int a, int b, int c); void GetSum(); }; int Myclass::sum = 0; //定义并初始化静态数据成员 Myclass::Myclass(int a, int b, int c) { this->a = a; this->b = b; this->c = c; sum += a + b + c; } void Myclass::GetSum() { cout << "sum=" << sum << endl; } .. note:: 静态成员函数可以调用构造函数,调用构造函数并不需要 ``this`` 指针。当构造函数是私有的,不能像普通类那样实例化,这时候可以通过静态成员函数调用构造函数(比如在实现单例的时候)。 extern: 修饰函数、变量 ------------------------ .. highlight:: cpp 修饰符 ``extern`` 用在变量或者函数的声明前,用来说明 **“此变量/函数是在别处定义的,要在此处引用”** 。 在别的文件中如果想调用 ``file1.c`` 中的变量 ``a`` ,只须用 ``extern`` 进行声明即可调用 ``a`` : :: extern int a; // file2.c extern "C" int a; // file3.cpp 在这里要注意 ``extern`` 声明的位置对其作用域也有关系,如果是在 main 函数中进行声明的,则只能在 main 函数中调用,在其它函数中不能调用。 其实要调用其它文件中的函数和变量,只需把该文件用 ``#include`` 包含进来即可,但是用 ``extern`` 会加速程序的编译过程,这样能节省时间。 .. note:: - 全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程。在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用该全局变量。 - 全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。 - C++ const 全局常量具有静态/内部链接,这与 C 语言不同。C++ 编译器优化全局常量,不为其保留任何空间。如果尝试在其他文件中通过 extern 使用该全局常量,则出现编译错误( *无法解析的外部符号 unresolved external symbol* )。解决此错误的一种方式是在头文件中进行 const 全局常量初始化,在需要使用该全局常量的源文件中 include 该头文件。在不同源文件中对该常量进行取址( ``&`` ),会得到不同的地址,这说明每个源文件都有一份常量的定义,而不是共享一个常量。C 编译器对定义在头文件的 const 常量会报错。 extern "C" {} ---------------------- .. code-block:: cpp :linenos: #ifndef HEADER_INCLUDED // 条件编译,避免重复包含头文件 #define HEADER_INCLUDED #ifdef __cplusplus // extern "C" 只用在 c++ 文件中 extern "C" { #endif /* __cplusplus */ #include "c.h" char* strcpy(char*,const char*); /*................................. * do something else *................................. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* HEADER_INCLUDED */ ``extern "C"`` 中的 ``C`` ,表示的一种编译和连接规约,表明它按照类 C 的编译和连接规约来编译和连接,而不是一种语言。 ``C`` 表示 **符合C语言的编译和连接规约的任何语言** ,如 Fortran、assembler 等。 ``extern "C"`` 的真实目的是实现 **类C** 和 C++ 的混合编程。 参考资料 --------------- 1. C/C++中的static关键字详解 https://www.cnblogs.com/qintangtao/p/3285937.html 2. C++项目中的extern "C" {} https://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html 3. 浅谈C/C++中的static和extern关键字 https://www.cnblogs.com/dolphin0520/archive/2011/04/20/2022701.html