news 2026/7/2 3:26:47

【静态初始化与动态初始化】基础介绍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【静态初始化与动态初始化】基础介绍

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
      • 一、前置概念:静态存储期(Static Storage Duration)
      • 二、静态初始化(Static Initialization):编译期确定,程序启动前完成
        • 1. 定义
        • 2. 两类静态初始化(零初始化 → 常量初始化)
        • 3. 示例(各类静态存储期变量的静态初始化)
      • 三、动态初始化(Dynamic Initialization):运行期计算,时机分场景
        • 1. 定义
        • 2. 动态初始化的触发时机(核心区分)
        • 3. 示例(各类静态存储期变量的动态初始化)
      • 四、关键误区纠正
        • 1. 动态初始化 ≠ 仅局部静态变量
        • 2. 初始化时机 ≠ 初始化类型
      • 五、补充规则(结合 C++17 inline 静态成员)
        • 1. constexpr 静态成员必然是静态初始化
        • 2. 零初始化的兜底作用
        • 3. 静态初始化顺序问题(SSIO)
      • 六、核心总结表格

前言

问题来源

去年也碰到过这个静态初始化与动态初始化,当时看几篇文章也一知半解
今天再记录下


程序启动前的初始化就属于静态初始化,如全局变量、全局静态变量、类的静态成员变量,第一次使用前的初始化就叫作动态初始化如局部静态变量,是这样吗

要彻底理解「静态初始化」和「动态初始化」,首先需要纠正你的核心误区:这两个概念的划分依据是「初始化值是否能在编译期确定」,而非变量的存储位置(全局/类静态/局部静态)或初始化时机;「静态存储期」(全局、类静态、局部静态变量的共同属性)是变量的生命周期特征,和「静态初始化」是完全不同的概念。

下面从「核心定义」「分类详解」「误区纠正」「实战示例」四个维度展开,结合 C++17 inline 静态成员场景讲透:

一、前置概念:静态存储期(Static Storage Duration)

先明确范围:所有属于「静态存储期」的变量,生命周期从程序启动程序结束(存储在数据段.data/.bss),包括:

  1. 命名空间作用域的全局变量(如int global_val = 10;);
  2. 类的静态成员变量(如class Test { inline static int val = 20; };);
  3. 函数内的局部静态变量(如void func() { static int local_val = 30; });
  4. namespace内的static变量(如namespace N { static int n_val = 40; })。

这些变量都可能是「静态初始化」或「动态初始化」—— 关键看初始化表达式的性质,而非变量属于哪一类。

二、静态初始化(Static Initialization):编译期确定,程序启动前完成

1. 定义

静态初始化是指:变量的初始化值能在编译/链接阶段完全确定(无需运行时计算),初始化在「程序启动后、main()执行前」的「静态初始化阶段」完成(是最早的初始化步骤)。

2. 两类静态初始化(零初始化 → 常量初始化)

所有静态存储期变量都会先经历「零初始化」,若有显式的常量表达式初始化,则覆盖为「常量初始化」(均属于静态初始化):

类型说明示例
零初始化(默认)编译器自动将变量初始化为“零值”(与类型相关),无显式初始化时兜底static int a;→ 初始化为 0
常量初始化(覆盖)显式初始化且表达式是「常量表达式(constant expression)」,覆盖零初始化static int b = 42;→ 42
3. 示例(各类静态存储期变量的静态初始化)
// 1. 全局静态变量(静态初始化)staticintglobal_static=10;// 常量表达式 → 常量初始化staticintglobal_uninit;// 无显式初始化 → 零初始化(值为0)// 2. 类inline静态成员(静态初始化,C++17)classTest{// constexpr隐式inline,常量表达式 → 静态初始化staticconstexprintmax_val=100;// inline + 常量表达式 → 静态初始化inlineconststaticdoublepi=3.14159;};// 3. 局部静态变量(静态初始化,易被误解为“动态”)voidfunc(){// 常量表达式 → 静态初始化(初始化在程序启动前完成,而非第一次调用func时)staticintlocal_static=30;}

三、动态初始化(Dynamic Initialization):运行期计算,时机分场景

1. 定义

动态初始化是指:变量的初始化值无法在编译期确定(初始化表达式不是常量表达式),需要运行时计算,初始化在「程序启动后」完成(具体时机分场景)。

2. 动态初始化的触发时机(核心区分)

这是你之前疑惑的“第一次使用前”的本质—— 动态初始化的时机分两种,而非“动态初始化=局部静态”:

变量类型动态初始化时机核心特点
非局部静态存储期变量main()执行前的「pre-main 阶段」跨编译单元初始化顺序未定义
局部静态存储期变量变量第一次被使用时(函数首次执行到该变量)C++11 后线程安全
3. 示例(各类静态存储期变量的动态初始化)
// 辅助函数:运行时才能确定值(非常量表达式)intget_runtime_val(){returnrand();// rand()是运行时函数,无法编译期确定}// 1. 全局静态变量(动态初始化:pre-main 阶段)staticintglobal_dyn=get_runtime_val();// 动态初始化(pre-main 阶段执行)// 2. 类inline静态成员(动态初始化:pre-main 阶段)classTest{// inline静态成员,初始化值非常量表达式 → 动态初始化inlinestaticintdyn_val=get_runtime_val();};// 3. 局部静态变量(动态初始化:第一次使用时)voidfunc(){// 第一次调用func()时初始化,后续调用复用已初始化的值(C++11后线程安全)staticintlocal_dyn=get_runtime_val();}

四、关键误区纠正

你之前的理解「程序启动前=静态初始化,第一次使用前=动态初始化(局部静态)」存在两个核心偏差:

1. 动态初始化 ≠ 仅局部静态变量

非局部静态变量(全局、类静态)也会有动态初始化,只是时机在main()前(pre-main 阶段),而非第一次使用时;
反过来,局部静态变量也可能是静态初始化(如static int a = 10;)—— 它的初始化值是常量表达式,因此仍在程序启动前完成,只是作用域局限于函数内。

2. 初始化时机 ≠ 初始化类型

「静态初始化/动态初始化」的核心是“值是否编译期确定”,而非“何时初始化”:

  • 静态初始化:必然在程序启动前完成(pre-main 阶段);
  • 动态初始化:可能在 pre-main 阶段(非局部)或第一次使用时(局部)完成。

五、补充规则(结合 C++17 inline 静态成员)

1. constexpr 静态成员必然是静态初始化

C++17 中constexpr static成员隐式inline,其初始化表达式必须是常量表达式,因此必然属于静态初始化,无需运行时计算:

classTest{staticconstexprintmax=100;// 静态初始化(编译期确定)};
2. 零初始化的兜底作用

即使静态存储期变量未显式初始化,编译器也会先执行零初始化(静态初始化的一种):

classTest{inlinestaticintuninit_val;// 零初始化→0(静态初始化)};
3. 静态初始化顺序问题(SSIO)

跨编译单元的非局部静态变量,动态初始化的顺序未定义,可能导致“未初始化访问”:

// file1.cppstaticinta=get_runtime_val();// 动态初始化(pre-main)// file2.cppstaticintb=a+1;// 危险:a可能未初始化(顺序不确定)

解决方法:用局部静态封装(Meyers单例),利用“第一次使用时初始化”的特性。

六、核心总结表格

维度静态初始化动态初始化
核心判断初始化表达式是常量表达式初始化表达式非常量表达式
计算时机编译/链接期运行期
执行时机程序启动前(pre-main)非局部:pre-main;局部:第一次使用
示例(inline静态)inline static constexpr int a=10;inline static int b=rand();
线程安全无(pre-main 单线程)局部静态:C++11后线程安全;非局部:不安全

简言之:

  • 只要初始化值能“写死在编译产物里”,就是静态初始化(程序启动前完成);
  • 只要需要运行时计算(如调用函数、读取运行时状态),就是动态初始化(时机分非局部/局部);
  • C++17 inline 静态成员只是简化了定义语法,其初始化类型(静态/动态)仍遵循上述规则。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 11:41:19

STM32低功耗模式下运行ModbusRTU的实践方法

STM32低功耗ModbusRTU实战:如何让工业通信“休眠中待命”你有没有遇到过这样的困境?一个电池供电的远程温湿度传感器,部署在无人值守的野外。它需要每隔几秒上报一次数据,但主站也可能随时通过ModbusRTU下发配置指令——比如修改采…

作者头像 李华
网站建设 2026/7/1 22:58:31

个人免费使用Sonic是否有次数限制?目前无明确限制

Sonic数字人生成技术深度解析:轻量级、高精度与免费使用的实践路径 在短视频内容爆炸式增长的今天,越来越多的创作者和企业开始尝试用数字人来替代真人出镜——无论是制作产品讲解、课程录制还是客服应答视频。然而,传统数字人方案往往依赖昂…

作者头像 李华
网站建设 2026/6/26 11:44:11

如何为Sonic贡献代码?CONTRIBUTING.md文件阅读指南

如何为Sonic贡献代码?CONTRIBUTING.md文件阅读指南 在虚拟内容爆发式增长的今天,数字人已不再是影视特效的专属技术。从直播间里的24小时主播,到教育平台上娓娓道来的AI教师,越来越多的应用场景呼唤一种低成本、高质量、易部署的说…

作者头像 李华
网站建设 2026/6/30 16:02:37

【毕业设计】SpringBoot+Vue+MySQL 医院档案管理系统平台源码+数据库+论文+部署文档

摘要 随着信息技术的快速发展,医疗行业对档案管理的效率和质量提出了更高要求。传统的医院档案管理方式依赖纸质文档和人工操作,存在信息检索困难、数据易丢失、管理成本高等问题。数字化档案管理系统能够有效解决这些问题,提升医院运营效率和…

作者头像 李华