c++ static const extern修饰变量
static关键字
在 C++ 中,static 变量的生命周期贯穿整个程序的执行过程。这是 static 最核心的特性之一。
一句话总结:
static 变量只初始化一次,存在于整个程序运行期间,直到程序结束时被销毁。
详细解释:不同作用域中的 static 变量
1. 函数内的 static 变量(局部静态变量)
#include <iostream>
void counter() {
static int count = 0;
count++;
std::cout << count << std::endl;
}
int main() {
counter();
counter();
counter();
}
//输出
1
2
3
- 生命周期:从第一次调用函数开始初始化,只初始化一次,直到程序结束。
- 作用域:只在当前函数内可见。
- 用途:用于保留函数调用间的状态(计数器、缓存等)。
2. 类中的 static 成员变量
class A {
public:
static int value;
};
int A::value = 10;
- 生命周期:从程序启动(或第一次使用)到程序结束。
- 作用域:属于整个类,而不是某个对象。
- 用途:在类的所有对象之间共享数据。
3. 全局或文件作用域的 static 变量
static int global_var = 100;
- 生命周期:从程序启动到结束。
- 作用域:只在当前源文件中可见(内部链接性)。
- 用途:防止变量被其他文件访问(封装)。
关键点小结:
| 用法位置 | 生命周期 | 作用域 | 初始化次数 | 示例用途 |
|---|---|---|---|---|
| 函数内 | 程序整个运行期 | 当前函数内 | 只初始化一次 | 函数调用次数计数器 |
类中 static 成员 |
程序整个运行期 | 所有类实例共享 | 在类外定义时初始化 | 配置值,共享状态 |
文件作用域(全局 static) |
程序整个运行期 | 当前源文件 | 一次 | 避免命名冲突 |
static vs 普通变量
| 特性 | 普通局部变量 | static 局部变量 |
|---|---|---|
| 存储位置 | 栈(stack) | 静态存储区(data segment) |
| 生命周期 | 每次进入函数时创建,退出函数时销毁 | 程序整个运行周期 |
| 初始化 | 每次调用都初始化 | 只初始化一次 |
const关键字
const 修饰变量、指针和引用对照表
| 声明形式 | 中文含义 | 是否可改指针指向 | 是否可改指针指向的数据 |
|---|---|---|---|
int a = 10; |
普通变量 | ✅ | ✅ |
const int a = 10; |
常量,值不可变 | ✅ | ❌(值不可修改) |
int* p |
指向 int 的普通指针 | ✅ | ✅ |
const int* p 或 int const* p |
指向 常量 int 的指针 | ✅ | ❌(*p 不可修改) |
int* const p |
常量指针,不可改变地址 | ❌ | ✅ |
const int* const p |
指向常量的常量指针 | ❌ | ❌ |
int& ref = a; |
普通引用 | ❌(引用不能重新绑定) | ✅ |
const int& ref = a; |
指向常量的引用(只读引用) | ❌ | ❌ |
const int& ref = 5; |
绑定右值(临时值) | ❌ | ❌ |
用法技巧总结:
| 应用场景 | 推荐写法 | 说明 |
|---|---|---|
| 不可修改参数(值类型) | void f(const int x) |
仅防止函数体内修改 |
| 不可修改参数(引用类型) | void f(const std::string& s) |
避免复制,防止修改,最常见 |
| 函数返回不可修改值 | const std::string& getName() |
保证返回值不能被改 |
| 静态类内常量 | static const int MAX = 100; |
编译期常量,可直接类内初始化 |
| 编译期常量(推荐) | constexpr int x = 100; |
C++11 后更推荐 |
快速记忆
// const修饰*p则*p不能改,修饰p则p存储的地址不能改
const int* p1 = &a; // *p1 不能改
int* const p2 = &a; // p2 不能改
const int* const p3 = &a; // p3 和 *p3 都不能改
extern 是 C++ 中的一个用于声明变量或函数而非定义的关键字,主要用于跨文件共享变量或函数。
总结:
extern表示:“这个变量/函数是在别处定义的,我这里只是引用它。”
extern
C++ 是编译型语言,编译时每个 .cpp 文件单独编译,链接时才合并。
- 如果两个文件都定义同一个变量,会重复定义错误。
- 用
extern,可以在一个文件中声明变量或函数,在另一个文件中定义它。
基本用法
1. 声明全局变量
// config.cpp
int g_value = 42; // 定义
// main.cpp
extern int g_value; // 声明
std::cout << g_value; // ✅ 合法
extern声明变量,不分配内存- 定义必须在其他文件中且只能出现一次
2. 声明函数(常见)
// utils.cpp
void hello() {
std::cout << "Hello" << std::endl;
}
// main.cpp
extern void hello(); // 声明
- 一般我们在头文件中写
extern函数声明,然后在.cpp文件中定义
与 const 联用:特别注意
C++ 中 extern 与 const 关键字连用的情况 —— 这是许多初学者容易混淆的地方,尤其涉及链接属性(linkage)*和*跨文件共享常量时。
简单例子
// file1.cpp
const int x = 42;
// file2.cpp
extern const int x; // ❌ 错误:undefined reference to `x`
为什么会报错?让我们从原理讲起。
const 变量的默认链接属性:内部链接(internal linkage)
在 C++ 中:
const int a = 5;
等价于:
static const int a = 5;
也就是说,const 默认只在当前编译单元(.cpp 文件)中可见,不会暴露给其他文件。
如何让 const 跨文件共享?
✅ 方法一:extern const + 定义在 .cpp 文件
cpp复制编辑// config.h
#pragma once
extern const int BUFFER_SIZE;
// config.cpp
const int BUFFER_SIZE = 4096;
// main.cpp
#include "config.h"
std::cout << BUFFER_SIZE << std::endl; // ✅ 正常使用
💡 此时
extern const是“声明”,而const是“定义”。
✅ 方法二:用 constexpr(C++11 起)
constexpr 变量默认有 external linkage,可以被多个 .cpp 文件引用而无需 extern。
cpp复制编辑// config.h
constexpr int BUFFER_SIZE = 4096; // 编译期常量,可直接头文件定义
// main.cpp
std::cout << BUFFER_SIZE << std::endl;
推荐:
constexpr是现代 C++ 推荐的方式,简洁、安全、无重复定义问题。
连接性
Linkage(连接性)*决定了一个名字(变量、函数、常量)在*多个源文件中是否共享同一个实体(内存地址)。
一、对比:external linkage vs internal linkage
| 特性 | external linkage(外部连接) |
internal linkage(内部连接) |
|---|---|---|
| 是否跨文件可见 | ✅ 可以被其他 .cpp 文件访问 |
❌ 只在当前 .cpp 文件可见 |
| 是否共享定义 | ✅ 所有文件共享同一个变量或函数 | ❌ 每个 .cpp 拥有自己的拷贝 |
| 如何实现 | 默认的函数、全局变量;用 extern 声明 |
使用 static 修饰 |
| 编译器错误类型 | multiple definition(重复定义)常因重复 external linkage |
名字冲突少,局部化 |
二、举例说明
external linkage:全局变量或函数(默认)
// file1.cpp
int x = 42; // x 有 external linkage
void foo() {} // 函数默认也是 external linkage
// file2.cpp
extern int x; // 引用 file1.cpp 的 x
void foo(); // 引用 file1.cpp 的 foo
编译器会将 x 和 foo 视为跨文件共享的同一个实体。
internal linkage:static 修饰全局变量或函数
// file1.cpp
static int x = 42; // x 只能在 file1.cpp 中访问
static void foo() {} // 只能在 file1.cpp 中使用
// file2.cpp
static int x = 999; // 和 file1.cpp 的 x 是完全不同的变量
每个文件有自己的版本,不互相干扰。
三、const 的默认连接性是 internal linkage!
// config.h
const int MAX_SIZE = 1024; // ⚠️ 每个包含 config.h 的 .cpp 文件都有一份副本
// main.cpp, utils.cpp 都包含 config.h → 产生 multiple definition
🔧 解决方法: 加 extern:
// config.h
extern const int MAX_SIZE;
// config.cpp
const int MAX_SIZE = 1024;
或改用 constexpr(它的默认链接性是 external linkage)。
四、总结
| 修饰符 | 默认连接性 | 可否跨 .cpp 文件 |
是否共享实体 | 用途 |
|---|---|---|---|---|
int x = 1; |
external | ✅ 是 | ✅ 共享 | 跨文件变量、函数 |
static int x = 1; |
internal | ❌ 否 | ❌ 不共享 | 文件私有变量或函数 |
const int x = 1; |
internal | ❌ 否 | ❌ 不共享 | 每个文件都单独复制(要注意) |
extern const int x; |
external | ✅ 是 | ✅ 共享 | 声明常量在别处定义 |
constexpr int x = 1; |
external | ✅ 是(C++17 后) | ✅ 共享 | 安全的编译期常量 |
未经作者同意请勿转载
本文来自博客园作者:aixueforever,原文链接:https://www.cnblogs.com/aslanvon/p/18929772

浙公网安备 33010602011771号