【C++】全局变量/静态变量的初始化时机

C中全局变量和局部变量的初始化问题 在C中初始化一个全局变量  和  在一个函数中初始化一个局部变量, 如果初始化时不赋值默认值都为0吗? 不是的。只有全局变量初始化时的默认值为0,而局部变量默认值是不确定的。所以,局部变量在使用之前一定要先赋值,如果基于一个不确定的值做后续运算必然会引入bug。 下面看一个错误的例子: #include int add_range(int low, int high) { int i, 阅读详情

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


一、全局变量下断点调试

现有如下代码

#include <iostream>

int a = 10;
static int b;
MyClass c;
static MyClass d;

int main() 
{
    return 0;
}

首先,全局变量的初始化分为零初始化和动态初始化。对于基本类型,比如 int a=10,这是常量初始化,属于静态初始化的一部分,通常在编译时就完成,可能不会生成对应的执行代码,所以调试器可能无法在定义处下断点,因为那里没有可执行的指令。

然后,static int b,全局静态变量,默认初始化(零初始化),也是在程序加载时完成,同样可能没有对应的执行代码,所以断点可能无效。

接下来是自定义类的全局对象 c 和 d。类对象的初始化需要执行构造函数,这属于动态初始化,发生在程序启动阶段(main 函数之前),由运行时库调用构造函数。这时候会有对应的执行代码(调用构造函数的指令),所以在定义处下断点,调试器可能能捕捉到这个时机,因为构造函数的调用是有执行步骤的。

不过需要注意,调试器能否在全局变量定义处下断点,取决于是否有对应的代码位置。对于基本类型的初始化,因为是编译期或加载期完成,没有指令执行,所以断点无效。而类对象因为需要执行构造函数,会有代码执行,所以断点可能有效。

另外,静态全局变量(b 和 d)和非静态全局变量(a 和 c)的区别主要在作用域(文件内还是全局),但初始化时机类似,基本类型的静态初始化没有执行代码,类对象的动态初始化有执行代码。

所以总结:int a 和 static int b 是基本类型,初始化在编译或加载时,无执行代码,断点不能卡住;MyClass c 和 static MyClass d 需要执行构造函数,有执行代码,断点可以卡住。

在全局变量定义处设置断点能否“卡住”调试,取决于变量初始化过程是否会生成可被调试器捕获的执行代码。具体分析如下:

1. int a = 10; —— 不能卡住断点

  • 原因:
    基本类型全局变量的初始化(如int a=10)属于静态初始化(编译期即可确定初始值),由编译器在编译阶段直接将初始值写入数据段,程序加载时直接从二进制文件中读取该值,不会生成单独的执行代码(没有指令来“执行”这个初始化)。
    调试器需要有对应的机器指令才能设置断点,而这里没有可执行的代码,因此断点无效。

2. static int b; —— 不能卡住断点

  • 原因:
    全局静态变量(static修饰的全局变量)的初始化规则与普通全局变量一致。未显式初始化的基本类型(如int b)会进行零初始化(值为0),同样在编译期/程序加载阶段完成,无执行代码。
    调试器无法在没有指令的位置断住,因此断点无效。

3. MyClass c; —— 可以卡住断点

  • 原因:
    自定义类的全局对象初始化需要执行构造函数,这属于动态初始化(运行时执行代码)。程序启动阶段(main函数之前),运行时库会自动调用MyClass的构造函数来初始化c,这个过程会生成对应的执行代码(调用构造函数的指令)。
    调试器可以在构造函数执行的对应位置断住,因此断点有效。

4. static MyClass d; —— 可以卡住断点

  • 原因:
    全局静态类对象(static MyClass d)的初始化逻辑与普通全局类对象一致:需要执行构造函数,属于动态初始化,在main函数之前由运行时库触发,会生成执行代码。
    虽然static限定了其作用域(仅当前文件可见),但初始化过程仍有可被调试器捕获的指令,因此断点有效。

总结

  • 不能卡住断点:int a = 10;、static int b;(基本类型,静态初始化,无执行代码)。
  • 可以卡住断点:MyClass c;、static MyClass d;(类对象,动态初始化,需执行构造函数,有可调试的执行代码)。

核心区别在于:基本类型的全局变量初始化在编译/加载阶段完成,无执行代码;而类对象的全局变量需要运行时执行构造函数,存在可被调试器捕获的代码指令。

二、静态变量初始化时机

1. 局部静态变量

在C++中,局部静态变量(包括自定义类的静态局部对象)的初始化时机和特性如下:

  1. 初始化时机:
    局部静态变量在函数第一次被调用时进行初始化,且仅初始化一次。
    对于自定义类的静态局部对象,其构造函数会在这个时机执行。

  2. 未调用函数的情况:
    如果从未调用该函数,其中的静态局部对象不会被初始化,其构造函数也不会执行。

  3. 生命周期:
    一旦初始化完成,局部静态变量的生命周期会延续到整个程序结束(与全局变量类似),在main函数退出后才会执行析构函数(如果是类对象)。

示例代码说明:

#include <iostream>

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass构造函数执行" << std::endl;
    }
    
    ~MyClass() {
        std::cout << "MyClass析构函数执行" << std::endl;
    }
};

void func() {
    static MyClass obj; // 静态局部对象
    std::cout << "func()被调用" << std::endl;
}

int main() {
    std::cout << "main()开始" << std::endl;
    
    func(); // 第一次调用func(),触发obj的构造
    func(); // 第二次调用,不会再次构造
    
    std::cout << "main()结束" << std::endl;
    return 0;
}

输出结果:

main()开始
MyClass构造函数执行
func()被调用
func()被调用
main()结束
MyClass析构函数执行

如果注释掉main()中对func()的所有调用,那么obj的构造函数永远不会执行。

这种特性使得局部静态变量非常适合实现"懒汉式"单例模式,确保对象在第一次使用时才被创建。

2. 与全局变量对比

在C++中,全局变量和局部静态变量虽然都存储在静态存储区(生命周期贯穿整个程序),但它们的初始化时机存在显著差异,主要体现在初始化的触发条件和具体阶段上。以下是详细说明:

1. 全局变量的初始化时机

全局变量(包括全局作用域的变量、命名空间作用域的变量、类的静态成员变量)的初始化发生在程序执行之前,具体分为两个阶段:

(1)静态初始化阶段(编译期/加载期)
  • 对于内置类型(如int、double)或常量表达式初始化的变量,编译器在编译期即可确定初始值,直接将值写入目标文件的静态存储区。
    例如:int g_a = 10;(常量初始化)、int g_b;(零初始化,默认值为0)。
(2)动态初始化阶段(运行期,main函数执行前)
  • 对于需要运行时计算初始值的全局变量(如自定义类的对象、依赖其他变量的表达式),初始化发生在main函数执行之前,由程序的启动代码(CRT初始化代码)触发。
    例如:
    class MyClass { public: MyClass() { /* 构造函数 */ } };
    MyClass g_obj; // 动态初始化,构造函数在main前执行
    int g_c = g_a + 5; // 依赖其他变量,动态初始化
    

注
int g_c = g_a + 5;
这句话下断点是可以卡住的

核心特点:

  • 全局变量的初始化不依赖任何函数调用,无论是否被使用,都会在程序启动阶段完成初始化。
  • 所有全局变量的初始化在main函数执行前全部完成。

2. 局部静态变量的初始化时机

局部静态变量(函数内部定义的static变量)的初始化时机与全局变量完全不同:

(1)初始化触发条件

局部静态变量的初始化仅在函数第一次被调用时触发,且只初始化一次。
例如:

void func() {
    static MyClass obj; // 仅在func第一次被调用时初始化
    static int num = 100; // 仅在func第一次被调用时赋值
}
(2)初始化阶段(运行期,函数首次调用时)
  • 对于内置类型,第一次进入函数时执行初始化(如static int num = 100;)。
  • 对于自定义类的静态局部对象,其构造函数在函数第一次被调用时执行。
  • 如果函数从未被调用,局部静态变量不会被初始化(构造函数也不会执行)。

核心特点:

  • 初始化依赖函数的首次调用,是“按需初始化”。
  • C++11及以后标准保证局部静态变量的初始化是线程安全的(多线程下首次调用不会导致重复初始化)。

3. 关键差异对比

特性全局变量局部静态变量
初始化触发条件程序启动时(main前),不依赖函数调用函数第一次被调用时,依赖函数调用
初始化次数仅一次(程序启动阶段)仅一次(首次调用时)
未使用时是否初始化会初始化(无论是否被使用)不会初始化(函数未调用则不初始化)
构造函数执行时机main函数执行前函数第一次被调用时

4. 示例验证

#include <iostream>

class Test {
public:
    Test(const char* name) : m_name(name) {
        std::cout << m_name << " 构造函数执行" << std::endl;
    }
    ~Test() {
        std::cout << m_name << " 析构函数执行" << std::endl;
    }
private:
    const char* m_name;
};

// 全局变量
Test g_test("全局变量");

void func() {
    // 局部静态变量
    static Test l_test("局部静态变量");
    std::cout << "func() 被调用" << std::endl;
}

int main() {
    std::cout << "main() 开始" << std::endl;
    func(); // 首次调用func,触发局部静态变量初始化
    func(); // 再次调用,不触发初始化
    std::cout << "main() 结束" << std::endl;
    return 0;
}

输出结果:

全局变量 构造函数执行  // 全局变量在main前初始化
main() 开始
局部静态变量 构造函数执行  // 首次调用func时初始化
func() 被调用
func() 被调用
main() 结束
局部静态变量 析构函数执行  // 程序结束时销毁
全局变量 析构函数执行      // 程序结束时销毁

结论:

  • 全局变量的构造函数在main开始前执行,局部静态变量的构造函数在函数首次调用时执行。
  • 若注释掉main中对func()的调用,局部静态变量的构造函数不会执行,而全局变量的构造函数仍会执行。

总结

全局变量和局部静态变量的核心差异在于初始化是否依赖函数调用:

  • 全局变量是“主动初始化”,程序启动即完成,与是否被使用无关;
  • 局部静态变量是“被动初始化”,仅在函数首次调用时触发,实现了“懒加载”特性,这也是其常用于单例模式的原因。

3.同为静态存储区为什么初始化时机不同

静态变量存放在静态存储区,程序执行前会初始化,但局部静态变量为什么没有在执行前初始化,而全局变量会先初始化。首先要明确静态存储区的概念,确实全局变量、静态全局变量、局部静态变量都存放在静态存储区,但它们的初始化时机不同。

首先,全局变量(包括静态全局变量)属于静态存储期,它们的初始化发生在程序启动的静态初始化阶段(在 main 函数执行之前)。对于自定义类的全局对象,其构造函数会在这个阶段执行,也就是 main 之前。

而局部静态变量虽然也存放在静态存储区,但其初始化属于延迟初始化(lazy initialization),这是 C++ 标准明确规定的:局部静态变量在函数第一次被调用时才会初始化,而非程序启动时。这是为了避免不必要的初始化开销 —— 如果函数从未被调用,局部静态变量就不会占用初始化资源。

总结核心区别:

存储区域:全局变量和局部静态变量都在静态存储区(生命周期都是程序整个运行期间)。
初始化时机:
全局变量:在 main 函数执行前的静态初始化阶段完成(构造函数此时调用)。
局部静态变量:在函数第一次被调用时才初始化(构造函数此时调用)。
未使用情况:
全局变量:无论是否被使用,都会在程序启动时初始化(构造函数一定会执行)。
局部静态变量:如果函数从未被调用,不会初始化(构造函数永不执行)。

虽然同属静态存储区,但全局变量和局部静态变量的初始化时机存在差异 ——C++ 标准对它们的初始化策略做了不同设计,以平衡效率和确定性。


后续

全局变量(包括全局作用域的变量、命名空间作用域的变量、类的静态成员变量)的初始化发生在程序执行之前

    1. 看下类的静态变量与全局变量性质是否一直
    1. 全局变量与静态全局变量的区别,即static对全局变量作用域影响详解
静态变量初始化的时机 静态变量的内存分配和初始化 对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。由于内置变量无须资源释放操作,仅需要回收内存空间,因此程序结束后全局内存空间被一起回收,不存在变量依赖问题,没有任何代码会再被执行! C++引入了对象,这给全局变量的管理带领新的麻烦。C++的对象必须有构造函数生成,并最终执行析构操作。... 阅读详情

相关推荐

全局变量和静态(全局和局部)变量 什么时候初始化?

全局变量和静态(全局和局部)变量 什么时候初始化? 本文链接:https://blog.csdn.net/sunny04/article/details/18605273 1. 静态变量的初始化是在编译时进行,变量的赋值是在函数或程序运行时进行。 2. 静态变量只初始化一次,但可以通过赋值的方式多次修改静态变量的值。 3. 全局变量和静态变量 在进入 main 前被初始化 ...

a1809032425的博客 1万+

静态变量初始化

静态变量的初始化分为两个过程,一个是静态初始化,一个是动态初始化。 静态初始化在系统加载后执行第一条语句之前就已经完成。所以,可以认为所有的静态初始化过程是同步完成的。 动态初始化,则在main函数之前完成,对于同一个编译单元内的静态变量,动态初始化顺序等同于定义顺序,而对于跨编译单元的静态变量,初始化顺序未定义。 静态数据有两种:已初始化数据和未初始化数据。 在映像文件里,它们分别被放入 data 段和 bss段。只有 data 段的已初始化的数据才会真正被放入映像文件。 int a=5;//data 段

码农练功房的博客 5072

C++全局变量初始化的一点总结

注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。   什么时候初始化   根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局变量的初始化可以认为分成以下两个阶段(c++11 N3690 3.6.2):   static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero init

静态变量的初始化

静态数据成员的使用方法和注意事项如下:   1、静态数据成员在定义或说明时前面加关键字static。   2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:     ::=   这表明:   (1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。   (2) 初始化时不加该成员的访问权限控制符private,

飞翔在北京的博客 6851

从Podfile到分享成功:ShareSDK小红书模块集成全流程实战(附视频分享代码)

本文详细介绍了iOS应用如何通过ShareSDK集成小红书分享功能的全流程,包括环境配置、SDK初始化、图片和视频分享实现,以及常见问题排查和性能优化策略。特别针对视频分享这一高频需求场景,提供了完整的代码示例和实战技巧,帮助开发者快速实现社交分享功能。

weixin_42540248的博客 218

全局变量什么时候被初始化,在进入main函数之前吗?

全局变量,static变量初始化时间 首先,静态局部变量和全局变量一样,数据都存放在全局区域内存分布情况,所以在主程序之前,编译器已经为其分配好了内存,但在C和C++中静态局部变量的初始化节点又有点不太一样。在C中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到在C语言中无法使用变量对静态局部变量进行初始化,在程序运行结束,变量所处的全局内存会被全部回收。而在C++中,初始化时在执行相关代码时才会进行初始化,主要是由于C++引入对象后,要进行初始化必须执行相应构造函数和析构函

dianqicyuyan的博客 9080

从NHANES到发表:如何用survey包完成符合CDC要求的统计分析(含完整R代码)

本文详细介绍了如何利用R语言的survey包,对美国国家健康与营养调查数据进行符合CDC要求的统计分析。文章重点解析了NHANES数据的复杂抽样设计、权重变量的正确选择与调整,并提供了从数据获取、清洗、构建调查设计对象到执行加权回归及生成发表级表格的完整R代码实战指南,帮助研究者避免常见错误,确保分析结果的准确性与可发表性。

weixin_29054245的博客 519

C++中全局变量,静态变量,静态局部变量 的初始化和内存分配问题

C/C++中全局变量,静态局部变量,局部变量的初始化问题

m0_51551385的博客 2989

Outlook日历同步全攻略:Win10+安卓+iOS三端无缝衔接(附常见问题解决)

本文提供了一份详尽的Outlook日历同步指南,帮助用户在Windows 10、安卓和iOS三端实现无缝衔接。文章深入解析了Exchange ActiveSync等核心同步原理,并给出了从账户创建到各设备(特别是华为手机)的具体配置步骤、进阶管理技巧以及针对同步失败、事件重复等常见问题的实战解决方案,旨在彻底解决跨平台日程管理的痛点。

l3m4n的博客 540

Silvaco TCAD仿真4——DeckBuild实战:从示例库到自定义设计

本文详细介绍了Silvaco TCAD仿真工具DeckBuild的实战应用,从示例库的使用到自定义设计的全过程。通过具体案例和参数修改技巧,帮助用户快速掌握TCAD仿真技术,提升半导体器件设计的效率和精度。特别适合需要从基础入门到进阶操作的工程师和研究人员。

weixin_29284657的博客 425

C/C++题目--内存管理

填空题: (1)从变量的定义位置分,可分为全局变量与局部变量。其中,局部变量定义在函数或复合语句中,供函数或复合语句中使用。 (2)变量的存储类型分为auto,extern,register, static。当声明一个静态(static)变量,它既具有局部变量的性质,又具有全局变量的性质。 (3)C++程序的内存分为4个区:全局数据区,代码区,栈区,堆区。全局变量,静态变量,字符串常量存放在...

用来学习的地方 1609

【FF-A】第四章 Concepts

SPM的责任分为两个组件:SPM调度器(SPMD)和SPM核心(SPMC)。这两个组件都可以访问整个物理地址空间,并且是受信任的计算基础的一部分。当无需区分这两个组件时,术语SPM被使用。这些组件的责任如下所示。SPMD 位于 EL3 中,以 AArch64 或 AArch32 执行状态运行。SPMC 可以与 SPMD 共存在 EL3 中,也可以位于相邻的异常级别,即 S-EL1 或 S-EL2。SPM 在启动时初始化 EL3 LSP,并在运行时促进它们与其他端点之间的通信。

baron-周贺贺-代码改变世界ctw 1190

C++和C中的静态变量

全局静态变量和全局变量的区别:全局静态变量的作用域仅仅在本文件中 C语言中的局部静态变量:在编译的时候就分配了内存,在main函数执行前进行初始化 C++语言中的局部静态变量:在第一次使用的时候分配内存并进行初始化。保证线程安全,即可以用在线程安全的单例模式中。 C++语言中的静态成员变量:在编译的时候分配内存,在main函数执行前进行初始化。 ...

sinat_41619762的博客 505

**Coffin-Manson 模型**在半导体功率循环测试中的理论背景、数学形式、应用场景,以及如何使用 **C#** 编程语言进行具体实现

Coffin-Manson 模型最初用于描述金属材料在低周疲劳(Low-Cycle Fatigue, LCF)下的寿命,后来被广泛应用于半导体功率器件(如 IGBT、MOSFET)的可靠性分析,特别是在功率循环测试中。如果你有具体数据(如 CSV 文件)、更复杂的模型要求(如 Bayerer 模型)或特定可视化需求,请提供,我可以进一步优化代码或添加功能!以下代码实现基本模型 ( N_f = A \cdot (\Delta T_j)^{-n} ) 的拟合,生成拟合曲线并预测寿命。我会结合你之前提到的。

专注于前沿技术的探索与实践,热衷于从代码逻辑、架构设计到行业应用等多维度深挖技术本质。期待在技术之路上与你共同成长~ 477

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

静态变量定义初始化

侵删

MFgming的博客 252

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

什么能在main()函数之前或之后执行

C/C++ main()主函数执行前和执行后还能运行其它的吗? 答案: 可以 例如: #include<iostream>#include<string>using namespace std;string str="预备......";cout<<str<<endl;int fn1(){cout<<"中间"<<e...

weixin_30894583的博客 112

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

C++中静态变量的初始化时间

本文表述了C++中静态变量的初始化时机

_Santiago的博客 1万+

C++静态变量初始化时机全解析

C++静态变量初始化时机全解析

xie__jin__cheng的博客 490

C++之static,静态变量

static的详解 关于初始化、内存、优点、指针、释放时机等问题。静态局部变量在全局数据区分配内存,局部变量在栈区分配内存。

m0_59052131的博客 6904

c++ 静态变量的初始化

c++ 静态变量的初始化

xie__jin__cheng的博客 477

全局对象_C++全局变量初始化

c++ 全局变量初始化的一点总结对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。由于内置变量无须资源释放操作,仅需要回收内存空间,因此程序结束后全局内存空间被一起回收,不存在变量依赖问题,没有任何代码会再被执行!C++引入了对象,这给全局变量的管理带领新的麻烦。C++的对象必须有构造函数生成,并最终执行析构操作。由...

weixin_39829497的博客 1636

C/C++ --- 全局变量初始化总结

注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。 什么时候初始化 根据 C++ 标准,全局变量的初始化要在 main 函数执行前完成,常识无疑,但是这个说法有点含糊,main 函数执行前到底具体是什么时候呢?是编译时还是运行时?答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局

xl928471061的博客 5574

全局变量,static变量初始化时间

原文 https://www.cnblogs.com/novice-dxx/p/7094690.html 本次上传主要是关于静态局部变量的初始化问题。 首先,静态局部变量和全局变量一样,数据都存放在全局区域,所以在主程序之前,编译器已经为其分配好了内存,但在C和C++中静态局部变量的初始化节点又有点不太一样。在C中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到在C...

hueru的博客 2万+
上一篇: 【QGIS源码阅读】QgsDataProvider::ReadFlags
下一篇: 【git使用场景】本地仓库与远程仓库存在独立历史
CSDN_RTKLIB
博客等级 码龄7年 148粉丝 402原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值