Skip to content

static / const / volatile / extern / mutable 关键字

一、static —— 三类作用(超高频)

1. static 局部变量

cpp
int counter() {
    static int n = 0;   // 只初始化一次,跨函数调用保留
    return ++n;
}
  • 存在全局/静态区(不是在栈上)。
  • 首次执行到定义时初始化一次,程序结束才销毁(单线程视角)。
  • 局部 static 用「局部静态初始化」保证线程安全(C++11 起编译器加锁,Meyers Singleton 基础)。

2. static 全局变量 / 函数(文件内)

  • 使变量/函数具有文件作用域(internal linkage),只在本 .cpp 可见,避免其它翻译单元重名冲突。
  • (现代风格倾向用 namespace {} 匿名命名空间 替代 static 全局。)

3. static 类成员(static 数据成员 + 静态成员函数)

  • static 数据成员:属于类(Class)而非某个对象,全类共享一份,需类外定义(C++17 可用 inline static 成员变量)。
  • static 成员函数:无 this、不能访问非 static 成员、不能是 virtual(无 this/vptr 可派发)。
  • 访问:ClassName::member 或对象 . 也可。
  • 初始化时机:程序启动于 main 之前完成(对全局 static 对象调用构造函数——「static initialization」)。

static 常问

  • static 局部变量 vs 全局变量:都静态存储,区别在作用域(前者函数内的局部可见,后者全局可见)。
  • 头文件里放 static 会怎样:每个 include 该头文件的翻译单元各持有一份独立 static 变量 → 不一致且耗内存。所以不要在头文件定义非 inline 全局/static

二、const —— 各种含义(最高频过滤题)

写法含义
const int x;普通常量,不可改
const int* p;指向const int:不可经 *p 改值,可改指向
int* const p;指针常量:p 不可改指向,可改 *p
const int* const p;都不可
const T& r;只读引用(只读临时生命周期延长由它做,const& 能绑定 rvalue)
T f() const;(成员)const 成员函数:承诺不修改本对象(除 mutable),this 是 const T*
顶层 const vs 底层 const顶层指对象本身 const,底层指指向物 const(C++ 面试进阶曾烤)
constexpr编译期常量表达式(C++11),比 const 更强的常量要求,用于模板/数组大小/switch case

常见作答要点:

  • const 便于避免意外修改、可作只读接口、能用于以 4 语义确保实参不可改。
  • const 成员函数可被非 const 对象调用?—— const 成员可由 const 或非 const 对象调用;非 const 成员只能被非 const 对象调用。
  • 想修一个 const 对象中特定字段 → mutable

mutable

  • 用于 const 函数内仍可修改的成员:缓存、锁、统计、std::mutex 等。
  • const 成员函数中,非 mutable 成员不可改;mutable 成员可改。

三、volatile(编译期优化相关,很多人要么不懂要么乱讲)

  • 告诉编译器:该变量可能被外部修改(硬件寄存器、信号处理、多线程其它 CPU 可见、中断等),每次访问都去真实内存读/写,不要优化地缓存进寄存器(禁止对它的读写进行重排合并消除)。
  • 不保证原子性:volatile 不是线程同步;多线程正确性仍需 mutex/atomic。
  • 常见场景:嵌入式寄存器、嵌入式标志(信号 handler 用的 sig_atomic_t 更标准)、内存映射 IO。
  • volatile + const 可以一起用(指向 readonly 可被外部改的寄存器,如 volatile const int* statusReg;)。

四、extern / extern "C"

  • extern 声明变量/函数在其它翻译单元定义,仅声明不定义(链接用)。
  • 头文件一般放声明(extern),.cpp 放定义——避免多文件重复定义(ODR)。
  • extern "C":告诉 C++ 链接器用 C 语言名字修饰(不 mangling) 规则,从而能调用/被调用 C 写的库
cpp
extern "C" {
    #include <some_c_header.h>  // 确保内部函数按 C 符号链接
    void c_func(int);
}

反过来 C++ 函数暴露给 C 用,也包 extern "C"。这样 ABI 一致、避免 C++ 名称修饰冲突。

五、综合记忆

  • 面向「对象内/资源持有」:static 属于类;面向「访问不改」:const;面向「外部/线程可改」:volatile;跨翻译单元/跨语言:extern。
  • 面试喜欢组合题:「const + static + 成员函数同时出现」「const_cast 去掉 const 后给它赋值是 UB(若原对象确实 const)」。

C++ 面试八股 · VitePress 版