【C++】extern,static inline再次总结
1. extern声明全局变量
extern用在声明变量处,不可赋初值,不分配内存。告诉链接器去别的目标文件找符号。
该变量定义在另一个文件,定义处不加extern。
使用该变量的地方,在使用处之前使用extern表明使用,链接器去其他文件找。
//a.h
extern int g_a; //声明
//a.cpp
int g_a = 10; //定义,外部链接
//b.cpp
extern int g_a; //使用前声明
void func()
{
g_a = 5; //使用
}
2. inline修饰变量
作用于静态成员
直接在.h文件的类定义中定义静态成员,而不需要在.cpp文件中通过int A::a=10
去定义了
class A
{
static int a = 10; //非法
}
class A
{
inline static int a = 10; //合法
}
作用于非成员变量
- 全局命名空间:
//header.hpp
int a = 10; //全局变量,全局命名空间。多个.cpp均引入该文件时,报重定义错误
inline int a = 10; //解决重定义问题
- 具名命名空间:
和全局命名空间一样的
//header.hpp
namespace qqq
{
int a = 10; //同上,只不过访问时需要指明具名命名空间
}
namespace qqq
{
inline int a = 10;
}
3. static inline修饰全局变量/命名空间内变量
“只在当前翻译单元可见”,每个翻译单元都会生成自己的独立实体。也就是:每个引入static inline头文件的cpp文件都会有自己独立的该变量。
static:作用于命名空间/全局变量时,表示:内部链接(每个翻译单元各有一份)。不用static修饰时默认是外部链接。
inline:“允许在多个翻译单元中出现重复定义”,但不会改变链接属性。
而所有cpp文件共用1个全局变量counter,要求:外部链接。
//所有cpp文件共用1个counter
// header.hpp
#pragma once
extern int counter; //声明
// globals.cpp
#include "header.hpp"
int counter = 0; //定义,全局变量默认外部链接。
4. 外部链接与内部链接
一句话先说明
- 外部链接(external linkage):名字在整个程序(所有翻译单元)中唯一,链接时可跨文件访问。
- 内部链接(internal linkage):名字仅在当前翻译单元内部可见,别的单元看不见、也链接不到。
1. 产生规则速查表
出现位置 | 默认链接 | 如何改成内部链接 | 备注 |
---|---|---|---|
命名空间/全局变量 | 外部 | 加 static |
int g; →外部,static int g; →内部 |
普通函数 | 外部 | 加 static |
void f(); vs static void f(); |
类的静态成员 | 外部 | 无法改成内部 | 始终外部 |
匿名命名空间 | 内部 | — | namespace { int x; } |
const 全局变量 | 内部(C++规则) | 加 extern 可显式外部 |
const int c = 1; 默认为内部 |
2. 代码对比
// a.cpp
int globalA = 0; // 外部链接
static int globalB = 0; // 内部链接,只能在 a.cpp 内使用
// b.cpp
extern int globalA; // 合法,链接到 a.cpp 的那一份
// extern int globalB; // 非法,链接器找不到
3. 链接阶段发生了什么
- 外部链接符号(如
globalA
)在所有目标文件中只有一份; - 内部链接符号(如
globalB
)在每个目标文件各有一份,名字互不干扰。
4. 常见误区
误区 | 正解 |
---|---|
“全局变量默认就是 extern” | 变量本身默认外部链接,但 extern 只是 声明语法,不是变量属性。 |
const int x = 1; 默认外部 |
错!默认内部链接(C++规则),需要 extern const int x = 1; 才能外部。 |
inline 会改变链接 |
不会,只影响“可重复定义”规则,不改变 static /extern 的链接属性。 |
5. 记忆口诀
全局/函数默认外部,要内部加
static
;
匿名命名空间天然内部;
const
全局默认内部,想外部加extern
。