C++全局变量初始化流程详解

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


前言

全局变量(包括static全局变量)的内存分配和初始化工作,是在main函数开始执行之前,由编译器、链接器和运行时库协同合作自动完成的。

编译流程概述

一个C++程序从源码到执行分为四个主要阶段:

  1. 预处理 (Preprocessing)

    • 处理内容: 处理以**#开头的预编译指令,如#include**(头文件展开)、#define(宏替换)、#ifdef(条件编译)等。
    • 输出: 一个纯粹的**.i或.ii**文本文件,不含任何预编译指令。
  2. 编译 (Compilation)

    • 处理内容: 将预处理后的源代码进行词法分析、语法分析、语义分析、优化,最终生成对应目标平台的汇编代码。
    • 输出: .s汇编语言文件或直接生成**.o**目标文件。
  3. 汇编 (Assembly)

    • 处理内容: 将汇编代码翻译成机器指令,并生成目标文件(Object File),通常是.o或.obj文件。目标文件包含了机器码、数据以及相关的元信息(符号表、重定位信息等)。
    • 关键点: 编译器会将在编译期已知初始值的全局/静态变量(如int g_var = 42;)放入目标文件的一个特定段(Section),通常是.data段。
  4. 链接 (Linking)

    • 处理内容: 将一个或多个目标文件(以及库文件)合并成一个最终的可执行文件(如.exe或.out)。链接器的主要任务是符号解析(找到每个符号、变量、函数的定义)和重定位(根据符号的最终地址修正代码中的引用地址)。
    • 输出: 可执行文件。

关键阶段:在main之前发生了什么?
操作系统加载器(Loader)将可执行文件读入内存并开始执行时,最先运行的并不是你的main函数。它会先运行一段被称为启动例程(Startup Routine) 或 运行时库(C Runtime Library, crt0) 的代码。这段代码是链接器在链接时悄悄添加到你的可执行文件开头的。

它的工作流程大致如下:

  1. 设置运行时环境: 初始化栈指针(SP)、帧指针(FP)等关键寄存器。
  2. 初始化静态数据: 这是最关键的一步!
  • 将来自可执行文件中.data段(已初始化的读写数据)的内容拷贝到对应的内存区域。
  • 将来自.bss段(未初始化或初始化为0的静态/全局数据)的对应内存区域清零。这就是为什么未初始化的全局变量默认是0。
  • 对于C++中更复杂的全局对象(如MyClass obj;),它们的构造函数也会在这一阶段被调用。
  1. 传递参数并调用main函数: 准备好argc和argv参数,然后正式调用你的main函数。
  2. 处理main的返回值: 当main函数返回后,启动例程会使用其返回值作为参数调用exit函数,完成一些清理工作,最后通过系统调用结束进程。

具体例子

让我们用两个简单的例子来验证这个过程。

例子1:基础数据类型

// main.cpp
#include <iostream>

int global_var = 42; // 已初始化的全局变量
static int static_global_var = 100; // 已初始化的static全局变量
int zero_var; // 未初始化的全局变量,默认在.bss段

int main() {
    std::cout << "global_var: " << global_var << std::endl;
    std::cout << "static_global_var: " << static_global_var << std::endl;
    std::cout << "zero_var: " << zero_var << std::endl;
    return 0;
}

编译和流程分析:

  1. 编译/汇编: 编译器看到global_var = 42;和static_global_var = 100;,知道它们的初始值,于是将它们的位置和初始值信息都放入目标文件的.data段。zero_var没有初始值,被放入.bss段。

  2. 链接: 链接器将所有目标文件的.data段和.bss段合并到最终的可执行文件中。

  3. 运行前: 操作系统加载器将可执行文件加载到内存。启动例程(crt0)执行:

    • 将可执行文件中.data段的内容(42和100)拷贝到为global_var和static_global_var分配的内存地址上。
    • 将zero_var所在的内存区域清零。
  4. 运行: 调用main函数。此时,所有全局变量都已经处于初始化后的状态,所以main可以直接使用它们。

例子2:C++全局对象

// main.cpp
#include <iostream>

class MyClass {
public:
    MyClass(int x) : value(x) {
        std::cout << "MyClass Constructor called! Value: " << value << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor called!" << std::endl;
    }
    int value;
};

MyClass global_obj(100); // 全局对象

int main() {
    std::cout << "main() function started." << std::endl;
    std::cout << "global_obj.value: " << global_obj.value << std::endl;
    return 0;
}

运行输出:

MyClass Constructor called! Value: 100
main() function started.
global_obj.value: 100
MyClass Destructor called!

分析:
输出顺序完美证明了我们的理论。

  1. 在进入main函数之前,启动例程不仅为global_obj分配了内存,还调用了它的构造函数。这就是“运行”的体现——运行了构造函数代码。
  2. main函数正常执行。
  3. 在main函数返回、程序结束之后,启动例程还负责调用全局对象的析构函数进行清理。

总结

全局和static全局变量的内存分配和初始化过程(对于简单类型是拷贝/清零,对于C++对象还包括构造函数调用)是由系统在main函数启动前自动完成的,而不是变量自己“运行”了。

这个机制保证了程序员在进入main函数时,所有全局资源都已经处于一个确定的可用的状态。

C/C++ 的全局变量初始化与不初始化的区别 在C语言里,全局变量如果不初始化的话,默认为0,也就是说在全局空间里:int x =0; 跟 int x; 的效果看起来是一样的。但其实这里面的差别很大,强烈建议大家所有的全局变量都要初始化,他们的主要差别如下:编译器在编译的时候针对这两种情况会产生两种符号放在目标文件的符号表中,对于初始化的,叫强符号,未初始化的,叫弱符号。连接器在连接目标文件的时候,如果遇到两个重名符号,会有以 阅读详情

相关推荐

C++全局变量操作

C++全局变量

OstrovskyWang的博客 2045

全局变量的初始化

注:以下例子仅是讨论C++语法,绝非推荐在实践中利用它们。例1extern int y;int x = y;int y = x;int main() ...{}例2extern int y;int x = y;int y = 3;int main() ...{}例3inf f()...{    return 3;}int x = y;in y = f();

Alex's walking 3775

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

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

全局变量和静态变量初始化总结

1 全局变量 c++保证,全局变量在main函数第一次使用它之前,就把它初始化好。【可以直接理解成在main函数执行前就初始化好】但这个初始化可细分为:编译时初始化和运行时初始化,即static initialization和dynamic initialization。 static initialization: 静态初始化,是针对于那些简单的、c++内部定义的数据结构,如int,double,bool及数组结构的初始化,又可分为zero和const两种方式。对于zero初始化,也就是我们没指定初值

Yohuna的博客 6031

问题:dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)

 1. 问题:Ubuntu安装软件的过程中出现依赖项的问题 “E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).” 按照指示执行如下两条命令都没有解决问题。 sudo apt-get -f install sudo apt-get --fix-broken ...

gloria_littlechi的博客 2万+

ArcGIS属性表汉字转拼音

接着我安装了一个编辑器“PyCharm Community Edition 2019.3.3\bin\pycharm64.exe”,在里面添加“pypinyin”包,然后将其设置为arcgis的编辑器和调试程序,还是失败;我在10.6的机器上折腾了上面几步,直到两周后脚本突然运行成功,我也不确定是哪一步导致pypinyin包配置成功,因此将心得体会写出来,如果过一段时间,打开10.2的机器运行脚本成功了,再写后续.......,按照“配置方法1:”进行尝试,显示配置失败。

2301_77413856的博客 1289

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

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

weixin_34161032的博客 741

当windows安装git时出现以下错误提示

Windows安装Git时出现多个系统配置设置失败错误(exit code 4294967295),提示包括无法设置textconv、LFS过滤器和SSL等配置项。关键问题在于scalar.exe版本不兼容,系统提示"该版本的scalar.exe与你运行的Windows版本不兼容"。解决方案是检查程序版本是否正确,下载与Windows系统兼容的正确版本重新安装即可。

沧澜的博客 1864

C++中全局变量的定义以及使用

C++中有时候会用到全局变量,可以用extern来修饰,主要有以下三步: 1、新建头文件global.h,里面定义全局变量,并用extern来修饰。 2、新建一个cpp文件进行变量初始化。 3、在需要使用的cpp文件中添加头文件global.h,直接使用全局变量即可。 ...

Brett 5万+

GEE去云处理代码段解读(位运算)

GEE去云处理代码段解读,包含位运算符号解读、bitwiseAnd()函数、eq()函数解读

jiekeheiguanglan的博客 2064

音乐生成 - 使用LSTM或Transformer模型进行音乐生成,如MIDI音乐生成。

在本篇博客中,我们将介绍如何使用LSTM和Transformer模型生成MIDI音乐。我们将首先概述音乐生成的一般流程,然后深入了解LSTM和Transformer模型的特点和实现。最后,我们将通过Python代码演示如何使用这两种模型生成MIDI音乐。

斌擎科技 1709

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

c++全局变量、静态变量初始化时机介绍

CSDN_RTKLIB的博客 1474

【项目实战】主流车载操作系统,QNX实时操作系统入门介绍

QNX是一种实时操作系统,自1980年代初期由Quantum Software Systems成立以来,已被广泛应用于各种行业和领域。QNX具有实时响应、高可靠性和分布式等特点,为各种设备提供了强大的底层操作系统平台。随着科技的不断发展和进步,QNX系统的应用范围和潜力也在不断扩大。本文将全面介绍QNX系统,包括其引言、背景、系统特性、应用领域和生态系统等方面。QNX作为一种实时操作系统,具有高效的实时性能、高可靠性、分布式、可剪裁性和可扩展性等特点。它在各个领域都有广泛的应用,并拥有一个庞大的生态系统。

奶爸的编程之路,也就一周冷个三天 3064

C++全局变量的初始化过程

全局变量在main()前完成初始化(调用构造函数) 在调用构造函数前,全局变量已分配空间,内存全0 多个全局变量的初始化,按照代码编译的顺序 注意:全局变量被访问前可能它还没有调用构造函数初始化。 如果一个项目中,多个dll都用到一个全局变量在共同的lib中,则每个dll都有一个独立的全局变量(地址不同),每个全局变量会初始化。 如下代码,A里面访问了全局变量g_b, 改变全局变量g_a...

vcpro126的专栏 2459

linux平台Modbus TCP测试

【代码】linux平台Modbus TCP测试。

无线互联&网络介绍 815

SAP SEGW 事物码里的 Function Import

开放数据协议(OData)包括标准的 CRUD (创建、检索、更新和删除)操作,这些操作映射到 HTTP 方法的 POST、GET、PUT/MERGE 和 Delete 几类。此外,OData还支持进一步的服务操作:,这些操作可以由HTTP方法GET或POST调用,用于处理不能映射到标准 CRUD 操作的任何内容。通过在数据模型中创建 ,可以在 service Builder 中实现此类额外的服务操作。例如,您可以为以下自定义操作创建函数导入:Work Item confirmation检查航班的可用性虽然

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 986

C++中全局变量、静态全局变量和全局常量详解

在C++中,全局变量、静态全局变量和全局常量是程序中常见的概念,它们在不同的情境下有着不同的用途和特性。让我们深入了解这些概念,以及它们的区别和用法。

马上到我碗里来的博客 1万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++全局变量初始化的顺序

虽然一直强调不要用全局变量。但是对于特殊的应用场合,还是有全局变量的使用(如某些多进程、多线程的共享资源),我们希望在首次运行(载入)时,系统能够帮助我们进行一些必要的初始化。 对不同的源文件中的全局变量,标准C++对全局变量初始化的顺序并没有要求。对于同一个原文件中,全局变量按照定义先后顺序初始化。 对于堆类型的全局变量的创建和构造,可能在一个构造函数中调用另一个未构造的全局变量,通常会检查另一个指针是否有效,并在无效时构造那个对象。这就出现一个问题: 一个指针在构造之前,被初始化。c/c++运行时

iMatt的专栏 2145

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++全局变量在本文件内部和外部.cpp文件中的定义与使用

记录: 情景:基于c++的代码: 工程中有2个.cpp文件,分别为a.cpp、b.cpp,我希望在b.cpp中声明并初始化几个全局变量bbb1、bbb2、bbb3,同时这几个全局变量的值我需要在a.cpp中得到。 需要做的工作: 在b.h中定义全局变量,采用private的形式: private: js_u8 bbb1; js_u8 bbb2; js_u8 bbb3; 定义获...

u010411205的博客 2113

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

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

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

weixin_39829497的博客 1636

C++全局变量、局部变量、成员变量初始化

1、实践是检验真理的唯一标准,废话不多说,上代码。 #include <QCoreApplication> #include <iostream> using namespace std; // 定义变量类 class Variable { public: Variable(const string& type) :_type(typ...

百里杨的博客 2451

C++:C++全局变量:看完还不懂全局变量来捶我

C++:C++全局变量:看完还不懂全局变量来捶我

C++ JAVA的专栏 1万+

关于C++未被初始化的变量

C++未初始化的变量

m0_64860543的博客 9091

关于C/C++中全局变量的初始化问题的深入思考

前言: 前日,在一次C++课程上,刘老师在举例说明构造函数和析构函数的功能时,提到了全局变量初始化时的构造函数的行为。构造函数在main函数之前初始化全局变量。当然在C++下我是深信不疑的。但随后老师声称C语言下的全局变量也是如此,因为C没有构造和析构函数,所以我们无法看到这一过程,在C++下可以在构造和析构函数中向屏幕打印信息,进而可以观察全局变量的初始化和生存期。 这个观点无疑使我心头一震

菜鸟的自留地-mooyang 2万+

C++全局变量内存分配和初始化顺序

C++全局变量内存分配和初始化顺序 1.局部变量规则 局部变量是在栈空间上,内存分配的顺序和代码的顺序是一致的 2.全局变量规则 2.1 初始化的全局变量 一般来说,对于初始化的全局变量,编译器遇到之后知道这是一个定义,会马上分配空间,例如: int ib = 10; int ia = 10; 这个分配的结果是:ia的地址在ib后面 2.2 未初始化的全局变量 对于未初始化的全局变量,编译器遇到之...

tsh123321的博客 1579

C++中的 .h 和 .cpp 区别详解

在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析。于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念。 对于以C起步,C#作为“母语”的我刚开始跟着导师学习C++对这方面还是感到很模糊。虽然我可以以C的知识面对C++的语法规范,用C#的思想领悟C++中类的使用。但是C#中定义和实现是都在一个文件中(其实都是在类里面),而使用...

deeplan_1994的博客 4万+
上一篇: UE4/UE5反射系统动态注册机制解析
下一篇: 深入浅出:UE4类型系统完整构建过程详解
努力的小钟
博客等级 码龄7年 292粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值