惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
宝玉的分享
宝玉的分享
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
量子位
博客园 - 司徒正美
V
V2EX
I
InfoQ
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
美团技术团队
N
Netflix TechBlog - Medium
L
LangChain Blog
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Stack Overflow Blog
Stack Overflow Blog
A
About on SuperTechFans
Microsoft Azure Blog
Microsoft Azure Blog

博客园 - 新西兰程序员

C++ 构造函数中的初始化参数列表initializer list C++中的线程thread,以及C++11中的std::atomic学习 Leetcode56 Merge Intervals 合并区间 -- C++实现 C++中的内存对齐 C++17中的结构化绑定Structured Binding C++中的函数参数是指针类型, 是按值传递 C++中异常处理机制中的栈展开stack unwinding C++实现链表反转 Linux中的性能分析工具 perf 来分析C++性能 C++17中新建一个类时,编译器默认生成的类成员函数 QT中的元对象系统 Leetcode 114 - 二叉树展开为链表 Leetcode65 有效数字 - 判断给定的字符串是否是一个有效数字 LettCode2289-Steps to Make Array Non-descreasing C#中的委托详解 C++中的std::function C++中的仿函数Functor C++中的const和constexpr异同比较 C++中的左值和右值,以及右值引用,移动语义 C++中传递参数是指针类型以及传入参数是指针的指针(**)详解 C++中GetTickCount函数学习 C++中以类的成员函数作为Windows callback函数需要设置成static函数 C#中的System.Security.SecureString学习 C++中的悬挂指针和野指针 C++中四种不同的对象生存方式(in stack, in heap, global, local static) C#中使用Parallel类来进行多线程并发编程 String类型转LPCTSTR -----理解C++中的字符串类型转换 C++中的虚函数和虚函数表 C++中基类指针指向派生类对象 数据结构 - 栈的学习
C++中的static关键字使用以及全局变量
新西兰程序员 · 2026-05-08 · via 博客园 - 新西兰程序员

今天想讲解一下C++中的static关键字的使用  ---  改变生命周期和改变作用域(链接属性)

static关键字的作用包括3条

1. static最重要的功能是隐藏

2.  static变量存放在静态存储区,所以它具备持久性

3. 也是因为static变量存放在静态存储区,所以它默认值是0

全局变量

我们知道,在C++中,全局变量是在所有函数体的外部定义的,程序的所有部分(其他文件的代码)都可以使用. 全局变量不受作用域的影响,它的生命周期一直到程序的结束。

全局变量也不是可以随便写在哪里,它得出现在所有的function, main,类定义之外的文件作用域里。

  • 定义位置必须是翻译单元顶层(即 .cpp 文件最外层),且不能嵌套在任何花括号内
  • 如果只声明不定义(比如用 extern int age;),那得确保某处有且仅有一个定义,否则链接失败
  • 头文件.h文件里绝不能放定义(如 int age = 20;),否则多文件包含会触发 ODR 违规,报错 multiple definition of 'age

对于全局变量,extern声明和定义的区别很关键

extern不是 “声明一个全局变量”,而是 “告诉编译器,这是个全局变量,在别处定义了,我只是用它,不占用内存”

  • 定义语句:int age = 300;  -----  分配存储,只能出现一次
  • 声明语句:extern int age; ----- 不分配空间,可出现在多个文件中(包括头文件)
  • 常见错误:在头文件.h文件里写 extern int age = 10; ----    = 10 让它变成定义,导致重复定义

static关键字 第1条解析 -- 隐藏

 我们来看一个例子

a.cpp

char x = 'A'; //全局变量
void msg()
{
   printf("Hello\n");
}

b.cpp

int main(void)
{
     extern char x; // extern关键字表示这是来自外部的一个全局变量
     printf("%c ", x);
  
     (void)msg();

     return 0;
}

输出结果  A Hello

这个例子中,我们可以看到,在a.cpp定义的全局变量x和全局函数msg, 都可以在b.cpp中使用  

那么,现在我想a.cpp中的这个全局变量和全局函数对其他文件隐藏,也就是说,其他文件比如b.cpp压根就看不到它,当然也不能使用它,怎么办呢 =>  这就要用到static关键字

在全局作用域(函数外,类外)使用static,它的核心作用是内部链接

含义:  被修饰的变量,函数或者对象, 只对“当前编译单元(.cpp文件)”可见

效果: 其他.cpp文件即使使用extern,也无法链接到它

#include <iostream>
using namespace std;

//static 隐藏全局变量,仅本文件可见
static int g_inner_val = 10;

//static 隐藏全局函数,仅本文件可见
static void inner_func()
{
      cout << "inner_func: 仅test.cpp可见" << endl;
}

//static 隐藏全局结构体实例, 仅本文件可见
static struct InnerObj
{
    void show()
    {
         cout << "g_inner_val = " << g_inner_val << endl;
    }
} g_inner_obj;

void public_func()
{
     cout << "public_func: 外部可调用" << endl;
     inner_func();  //本文件内部可以调用static 函数
     g_inner_obj.show(); //本文件内部可以调用static 对象
}

static关键字 第2条解析 -- 改变存储期,保持变量内容的持久

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化. 共有2种变量存储在静态存储区,全局变量和static变量 (像上面例子在全局变量前面加上static关键字,那这个变量是静态全局变量,它既是全局变量,又是静态变量,static的作用是隐藏它)

生命周期: 程序启动时分配内存(静态存储区),程序结束才释放

 我们来看一个例子,在函数内部的局部变量前加上static关键字,让这个局部变量存储在静态存储区  => 它经常用来实现计数器,单列模式

Counter.cpp

#include <iostream>
using namespace std;

void TestCounter()
{
      // 静态局部变量,只会初始化1次
      static int count = 0;
      count++;
      cout << "count = " << count << endl;
      
}

int main()
{
    TestCounter(); // 1
    TestCounter(); // 2
    TestCounter(); // 3

    return 0; 
     
}

 上面的例子中,可以看出,用static来修饰函数内的局部变量,有以下作用

  • 改变生命周期, 从栈区自动变量(函数结束销毁)变为静态存储区变量(程序结束才销毁).
  • 只初始化一次:  第一次执行到定义语句时初始化,后续调用函数不会重复初始化.
  • 保留变量值:函数多次调用时,变量会保留上一次的值
  • 作用域仅限当前函数,外部无法访问
  • 适合需要持久化状态的场景 (如 计数,缓存)

static关键字修饰类的成员

上面我们已经讲到static关键字修饰全局变量/函数,修饰函数内的局部变量。现在我们想来说一说用static关键字来修饰类中的成员,包括成员变量和成员函数

static静态数据成员是类的成员,而不是对象的成员

类的static静态成员函数属于整个类,而不是类的对象,所以它没有this指针. 这就导致了它仅能访问类的静态数据和静态成员函数

     关于这点,可以参看问我以前写的文章   https://www.cnblogs.com/wphl-27/p/18011014

  1. static类的静态成员变量

  • 所有对象共享同一个静态变量,不占用对象内存
  • 必须在类外初始化(类内仅声明)
  • 可通过类名::变量名 或 对象.变量名 访问

    2. static类的静态成员函数

  • 属于类,不属于某个对象,无this指针
  • 只能访问静态成员(静态变量/静态函数),不能访问非静态成员
  • 直接通过类名::函数名 () 调用,无需创建对象。

总结

修饰场景核心作用生命周期作用域
局部变量 持久化值,只初始化 1 次 程序全程 函数内
全局变量 / 函数 仅当前文件可见,防冲突 程序全程 当前源文件
类成员变量 所有对象共享,类独有 程序全程 类作用域
类成员函数 无 this 指针,类直接调用 - 类作用域