1. 声明和定义
当定义一个变量的时候, 就包含了对该变量声明的过程, 同时在内存张申请了一块内存空间. 如果在多个文件中使用相同的变量, 为了避免重复定义, 就必须将声明和定义分离开来. 定义是创建与名字关联的实体. 声明是让名字为程序所知, 当一个文件想要使用其他文件定义的某个变量, 则必须包含对那个文件的声明:
函数和变量的声明不会分配内存, 但是定义会分配相应的内存空间
函数和变量的声明可以有很多次, 但是定义最多只能有一次
函数的声明和定义方式默认都是 extern 的, 即函数默认是全局的
变量的声明和定义方式默认都是局部的, 在当前编译单元或者文件内可用
了解声明和定义对 static 和 extern 的理解有辅助作用. 比如 extern 就是在一处定义, 其他文件都只需要声明即可, 不可重复定义.
2. static& extern
2.1 static
一般局部变量是存储在栈区的, 局部变量的生命周期在其所在的语句块执行结束时便结束了. 但如果用 static 修饰局部变量, 那么这个变量就不会存储在栈区而是放在静态数据区, 其生命周期会一直持续到整个程序结束, 该变量只在初次运行时进行初始化, 且只进行一次, 但是它的作用域只能是在函数里面如下:
- void print(){
- static int z = 100;
- z++;
- cout <<z <<endl;
- }
- int main(){
- print();
- print();
- print();
- return 0;
- }
局部静态变量 z 只能在本文件的 print 函数里面访问, 一旦超出作用域范围, 就无法访问.
如果是 static 修饰的全局变量, 且实现的函数写在头文件 (h) 中, 在其他文件也可以访问, 如下:
- // a.h
- #ifndef A_H
- #define A_H
- #include<iostream>
- using namespace std;
- static char str[] = "hello";
- namespace sextern {
- void print1();
- void Fun1();
- void Fun1(){
- str[0] = 'l';
- }
- void print1(){
- cout <<"value" << str <<endl;
- cout << "address" << &str <<endl;
- }
- }
- #endif // A_H
- //b.h
- #ifndef B_H
- #define B_H
- namespace sextern{
- void Fun2(){
- str[0] = 'o';
- }
- void print2(){
- cout << "value" << str <<endl;
- cout << "address" << &str <<endl;
- }
- #endif // B_H
- //main.cpp
- #include "a.h"
- #include "b.h"
- using namespace sextern;
- int main(int argc, char *argv[])
- {
- sextern::Fun1();
- print1();
- sextern::Fun2();
- print2();
- print1();
- return 0;
- }
- // 结果如下
- /*
- * value lello
- * address 0x601058
- * value oello
- * address 0x601058
- * value oello
- * address 0x601058
- * 按 <RETURN> 来关闭窗口...
- */
发现将 static 全局变量写在头文件中, 所有文件的头文件的操作都会共享这个变量.
但如果是在源文件 (cpp) 中去操作这个静态全局变量, 则这个静态全局变量只能在当前文件有效, 但是在另外一个文件访问此静态变量, 会是该变量初始的默认值, 不会是其他文件中修改的值, 虽然它们有相同的初始内容, 但是存储的物理地址并不一样. 如下:
- //a.h
- #ifndef A_H
- #define A_H
- #include<iostream>
- using namespace std;
- static char str[] = "hello";
- namespace sextern {
- void Fun1();
- void print1();
- }
- #endif // A_H
- //a.cpp
- #include "a.h"
- namespace sextern {
- void Fun1(){
- str[0] = 'l';
- }
- void print1(){
- cout <<"value" << str << endl;
- cout << "address" << &str <<endl;
- }
- }
- //c.h
- #ifndef C_H
- #define C_H
- #include<iostream>
- using namespace std;
- namespace sextern {
- void Fun3();
- void print3();
- }
- #endif // C_H
- //c.cpp
- #include "c.h"
- #include "a.h"
- namespace sextern {
- void Fun3(){
- str[0] = 'o';
- }
- void print3(){
- cout <<"value" << str <<endl;
- cout << "address" << &str <<endl;
- }
- }
- #include "a.h"
- #include "c.h"
- using namespace sextern;
- int main(int argc, char *argv[])
- {
- sextern::Fun1();
- print1();
- sextern::Fun3();
- print3();
- print1();
- return 0;
- }
- // 结果如下
- /*
- * value lello
- * address 0x602064
- * value oello
- * address 0x60205e
- * value lello
- * address 0x602064
- * 按 <RETURN> 来关闭窗口...
- */
在 a.h 的头文件中定义了一个静态的全局变量 x, 不同文件的函数 fun1 和 fun3 会为每个包含该头文件的 cpp 都创建一个全局变量, 但他们都是独立的, 只在该 cpp 文件共享该变量. 所以一般定义 static 全局变量时, 都把它放在原文件中而不是头文件, 从而避免多个源文件共享, 就不会给其他模块造成不必要的信息污染. 如果想要在不同文件共享同一个全局变量, 这个时候就要用到 extern.
2.2 extern
当在某个文件定义了一个全局变量, 如果要在另一个文件去使用该变量, 如果再次去定义, 则会出现重复定义的问题, 这个时候就需要使用到声明, 对该变量的声明告诉编译器该变量在其他文件中已经定义, 在此处要去引用它. 上述的代码改成如下形式:
- //b.h
- #ifndef B_H
- #define B_H
- char str[] = "hello"; // 定义一个全局变量
- #endif // B_H
- //a.h
- #ifndef A_H
- #define A_H
- #include<iostream>
- using namespace std;
- extern char str[];
- namespace sextern {
- void Fun1();
- void print1();
- }
- #endif // A_H
- //a.cpp
- #include "a.h"
- namespace sextern {
- void Fun1(){
- str[0] = 'l';
- }
- void print1(){
- cout <<"value" << str << endl;
- cout << "address" << &str <<endl;
- }
- }
- //c.h
- #ifndef C_H
- #define C_H
- #include<iostream>
- using namespace std;
- extern char str[];
- namespace sextern {
- void Fun3();
- void print3();
- }
- #endif // C_H
- //c.cpp
- #include "c.h"
- namespace sextern {
- void Fun3(){
- str[0] = 'o';
- }
- void print3(){
- cout <<"value" << str <<endl;
- cout << "address" << &str <<endl;
- }
- }
- // 结果如下
- /*
- * value lello
- * address 0x602058
- * value oello
- * address 0x602058
- * value oello
- * address 0x602058
- * 按 <RETURN> 来关闭窗口...
- */
参考资料
详解 C/C++ 中的 static 和 extern
C/C++ 中 extern 关键字详解
来源: https://www.cnblogs.com/helloworldcode/p/11191231.html