当前位置: 首页 > news >正文

C++全局构造和初始化

片段摘自程序员的自我修养—链接、装载与库.pdf 11.4

程序在进入main之前,需要对全局对象进行构造初始化。

glibc全局对象进行构造初始化

gibc启动程序时会经过.init段,退出程序时会经过.finit段。这两个段中的代码最终拼接成_init()_finit(),这两个函数优先于/后于main函数执行。

_start->_init()->main()->_finit()

用户所有放在.init段的代码将在main函数之前执行,即全局对象的初始化。具体执行流程如下:

_start->__libc_start_main->__libc_csu_init->_init->__do_global_ctors_auxvoid __do_global_ctors_aux(void)
{/*call constructor functions*/unsigned long nptrs = (unsigned long)__CTOR_LIST__[0];
for(unsigned i = nptrs;i >= 1;i--)__CTOR_LIST__[i]
}

CTOR_LIST 存放所有全局对象的构造和初始化的函数指针。__do_global_ctors_aux从__CTOR_LIST__ 的下一个位置开始,按顺序执行函数指针,直到遇上NULL(__CTOR_END__),从而调用所有全局对象的构造函数。

那么__CTOR_LIST__ 是如何初始化的呢?
GCC编译器在编译的时候会遍历每个编译单元的全局对象,生成一个特殊函数_GLOBAL__I_HW,利用这个特殊函数对本编译单元的所有全局、静态对象进行初始化。

static void _GLOBAL__I_HW(void)
{Hw::Hw();//构造对象atexit(__tcf_l)
}

一旦目标文件里面有这样的函数,编译器则会在这个编译单元目标文件的.ctors放置一个指针,指向_GLOBAL__I_HW。即__CTOR_LIST__列表保存的是每个编译单元的_GLOBAL__I_HW函数指针。链接器则会将所有的目标文件的.ctors合并成一个.ctors段
__CTOR_LIST__ 代表所有.ctors的起始地址。
__CTOR_END__ 指向.ctors段的末尾。
在这里插入图片描述
所以如果想在main之前调用函数,只需要在.ctors段里面添加函数指针即可。

#include <stdio.h>
#include <stdlib.h>//main函数之前执行
__attribute((constructor)) void before_main()
{printf("====%s=====\n", __FUNCTION__);
}//main函数之后执行
__attribute((destructor)) void after_main()
{printf("====%s=====\n", __FUNCTION__);
}int main(int argc, char **argv)
{printf("=====entering %s.========\n", __FUNCTION__);printf("====exiting from main!===\n");return 0;
}

在这里插入图片描述

MSVC 全局对象进行构造初始化

msvc的入口函数mainCRTStartup

mainCRTStartup()
{..._initterm(__xc_a,__xc_z);...
}

其中__xc_a__xc_z是两个函数指针。而_initterm的内容则是:

typedef void (__cdecl *_PVFV)();
static void __cdecl _initterm(_PVFV* pfbegin,_PVFV* pfend)
{while(pfbegin < pfend){if(*pfbegin  != null)(**pfbegin)();++pfbegin;}
}

第一眼看上去和glibc几乎一模一样,__xc_a相当于指针的开始地址__CTOR_LIST____xc_z则相当于结束地址__CTOR_END__

那么msvc 是如何初始化__xc_a__xc_z的呢?

_CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = {NULL};
_CRTALLOC(".CRT$XCZ") _PVFV __xc_Z[] = {NULL};

其中_CRTALLOC定义

#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)#define _CRTALLOC(x) __declspec(allocate(x))

#pragma section("section-name",[,attributes])的作用是在obj的文件里创建名为section-name,并具有指定的attributes属性。所以上述两条指令实际生成了两个名为.CRT$XCA、.CRT$XCZ的段。__declspec(allocate(x)则表示变量将变量分配在段x里。所以__xc_a分配在.CRT$XCA__xc_z分配在.CRT$XCZ里。
msvc编译的时候,会为每一个编译单元生成.CRT$XCU(U是User的意思)的段。在这个段里面加入自身的全局初始化函数。链接的时候将所有相同属性的段合并。段根据字母A-Z的顺序排序
在这里插入图片描述
所以如果想在main之前调用函数,只需要在段(A-Z之间,不包含A,Z.CRT$XCB里面添加函数指针即可。

因为全局初始化函数在段.CRT$XCU里面,根据A-Z排序并执行。所以如果想要在全局构造函数之前执行,段名必须在U之前。如果想在全局构造函数之后main之前则段名必须在U之后。不包含A,Z

class CA
{
public:CA(){printf("CA::CA\r\n");}~CA(){printf("CA::~CA\r\n");}
};#define SECNAME ".CRT$XCB"#pragma section(SECNAME,long,read)
void foo()
{printf("foo \r\n");
}
typedef void(_cdecl* _PVFV)();
_declspec(allocate(SECNAME)) _PVFV dummy[] = { foo };CA g_obj;
int main()
{printf("main enter\r\n");printf("main exit\r\n");return 0;
}

.CRT$XCB段输出(先执行foo,在执行全局对象初始化,在执行main
在这里插入图片描述
.CRT$XCY段输出(先执行全局对象初始化,在执行foo,在执行main
在这里插入图片描述

Note:注意事项,如果在main函数之前想引用全局变量或者函数,此时全局变量的构造函数还没执行。可能结果和预期不一致。
demo: foo里面改变CA成员变量的值。

CA g_obj;void foo()
{g_obj.m_a = 10;printf("foo g_obj addr:%I64d g_obj.m_a=%d\r\n", &g_obj, g_obj.m_a);
}int main()
{printf("main enter\r\n");printf("foo g_obj addr:%I64d g_obj.m_a=%d\r\n", &g_obj, g_obj.m_a);printf("main exit\r\n");return 0;
}

在这里插入图片描述
虽然在foo里面改变了m_a,但是稍后执行段.CRT$XCU时此时会调用CA::CA导致m_a被重新赋值0

相关文章:

C++全局构造和初始化

片段摘自程序员的自我修养—链接、装载与库.pdf 11.4 程序在进入main之前&#xff0c;需要对全局对象进行构造初始化。 glibc全局对象进行构造初始化 gibc启动程序时会经过.init段&#xff0c;退出程序时会经过.finit段。这两个段中的代码最终拼接成_init()和_finit(),这两个…...

安全见闻-泷羽sec课程笔记

编程语言 C语言&#xff1a;一种通用的、面向过程的编程语言&#xff0c;广泛应用于系统软件和嵌入式开发。 C:在C语言基础上发展而来&#xff0c;支持面向对象编程&#xff0c;常用于尊戏开发、高性能计算等领域。 Java:一种广泛使用的面问对象编程语言&#xff0c;具有跨平台…...

游戏引擎学习第17天

视频参考:https://www.bilibili.com/video/BV1LPUpYJEXE/ 回顾上一天的内容 1. 整体目标&#xff1a; 处理键盘输入&#xff1a;将键盘输入的处理逻辑从平台特定的代码中分离出来&#xff0c;放入更独立的函数中以便管理。优化消息循环&#xff1a;确保消息循环能够有效处理 …...

【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )

文章目录 一、av_packet_ref 函数1、函数原型2、函数源码分析3、函数使用代码示例 二、av_packet_clone 函数1、函数原型2、函数源码分析 FFmpeg 4.0 版本源码地址 : GitHub : https://github.com/FFmpeg/FFmpeg/tree/release/4.0GitCode : https://gitcode.com/gh_mirrors/ff…...

【学习笔记】量化概述

Quantize量化概念与技术细节 题外话&#xff0c;在七八年前&#xff0c;一些关于表征的研究&#xff0c;会去做表征的压缩&#xff0c;比如二进制嵌入这种事情&#xff0c;其实做得很简单&#xff0c;无非是找个阈值&#xff0c;然后将浮点数划归为零一值&#xff0c;现在的Qu…...

同步互斥相关习题10道 附详解

PV操作 2016 某系统允许最多10个进程同时读文件F&#xff0c;当同时读文件F的进程不满10个时&#xff0c;欲读该文件的其他文件可立即读&#xff0c;当已有10个进程在读文件F时读&#xff0c;其他欲读文件F的进程必须等待&#xff0c;直至有进程读完后退出方可去读 在实现管…...

【Python · PyTorch】卷积神经网络 CNN(LeNet-5网络)

【Python PyTorch】卷积神经网络 CNN&#xff08;LeNet-5网络&#xff09; 1. LeNet-5网络※ LeNet-5网络结构 2. 读取数据2.1 Torchvision读取数据2.2 MNIST & FashionMNIST 下载解包读取数据 2. Mnist※ 训练 LeNet5 预测分类 3. EMnist※ 训练 LeNet5 预测分类 4. Fash…...

Git 拉取指定分支创建项目

一 背景 因为项目过大&#xff0c;只需要部分分支的代码即可。 二 实现 方法一&#xff1a;使用 --single-branch 参数 git clone 支持只拉取指定分支&#xff0c;而不是整个库的所有分支&#xff1a; git clone --branch <branch_name> --single-branch <reposi…...

CF862B Mahmoud and Ehab and the bipartiteness(二分图的性质)

思路&#xff1a;一个二分图是由两个集合组成的&#xff0c;同一个集合中的节点间不能连边&#xff0c;所以一个二分图最多有cnt[1]*cnt[2]条边&#xff0c;题目给出一个树的n-1条边&#xff0c;要我们添加最多的边数使他成为二分图&#xff0c;添加的边数就是cnt[1]*cnt[2]-n1…...

React Native 全栈开发实战班 :数据管理与状态之React Hooks 基础

在 React Native 应用中&#xff0c;数据管理与状态管理是构建复杂用户界面的关键。React 提供了多种工具和模式来处理数据流和状态管理&#xff0c;包括 React Hooks、Context API 以及第三方状态管理库&#xff08;如 Redux&#xff09;。本章节将详细介绍 React Hooks 的基础…...

传奇996_22——自动挂机

登录钩子函数中执行 callscript(actor, "../QuestDiary/主界面基础按钮/主界面基础按钮QM", "基础按钮QM")基础按钮QM执行了已下代码 #IF Equal <$CLIENTFLAG> 1 #ACT goto PC端面板加载#IF Equal <$CLIENTFLAG> 2 #ACT goto 移动端面板加载…...

faiss 提供了多种索引类型

faiss 多种索引类型 在 faiss 中&#xff0c;IndexFlatL2 是一个简单的基于 L2 距离&#xff08;欧几里得距离&#xff09;进行索引的索引类型&#xff0c;但实际上&#xff0c;faiss 提供了多种索引类型&#xff0c;支持不同的度量方式和性能优化&#xff0c;您可以根据需求选…...

比rsync更强大的文件同步工具rclone

背景 多个复制&#xff0c;拷贝&#xff0c;同步文件场景&#xff0c;最大规模的是每次几千万规模的小文件需要从云上对象存储中拉取到本地。其他的诸如定期数据备份&#xff0c;单次性数据备份。 rsync是单线程的&#xff0c;开源的mrsync是多线程的&#xff0c;但适用范围没…...

《业务流程--穿越从概念到实践的丛林》读后感一:什么是业务流程

1.1 流程和业务流程概念辨析 业务流程建模标准(BPMN)对于业务流程的定义:一个业务流程由为了配合一个组织性或技术环境而一系列活动组成。这些活动共同实现一个业务目标。 业务流程再造最有名的倡导者托马斯.H.达文波特对于流程和业务流程的定义:流程是一组结构化且可度量的…...

解决docker mysql命令行无法输入中文

docker启动时&#xff0c;设置支持中文 docker run --name mysql-container -e MYSQL_ROOT_PASSWORDroot -d mysql:5.7 --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci --default-time-zone8:00 进入docker时&#xff0c;指定LANG即可 docker exec -it …...

基于Java Springboot城市公交运营管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…...

Lc70--319.两个数组的交集(二分查找)---Java版

1.题目描述 2.思路 用集合求交集&#xff0c;因为集合里面的元素要满足不重复、无序、唯一。使得集合在去重、查找和集合操作&#xff08;如交集、并集、差集等&#xff09;中非常高效和方便。 3.代码实现 class Solution {public int[] intersection(int[] nums1, int[] nu…...

亿咖通科技应邀出席微软汽车行业智享会,分享ECARX AutoGPT全新实践

11月14日&#xff0c;全球出行科技企业亿咖通科技&#xff08;纳斯达克股票代码&#xff1a;ECX&#xff09;应邀于广州参加由微软举行的汽车行业智享会&#xff0c;揭晓了亿咖通科技对“AI定义汽车”时代的洞察与技术布局&#xff0c;分享了亿咖通科技汽车垂直领域大模型ECARX…...

Python教程:运算符重载

在Python中&#xff0c;运算符重载是通过定义特殊方法&#xff08;也称为魔术方法&#xff09;来实现的&#xff0c;这些特殊方法允许类的实例像内置类型那样使用运算符。 Python提供了一系列这样的特殊方法&#xff0c;用于重载各种运算符。 以下是一些常见的运算符重载特殊…...

AWTK VSCode 实时预览插件端口冲突的解决办法

AWTK XML UI 预览插件&#xff1a;在 vscode 中实时预览 AWTK XML UI 文件&#xff0c;在 Copilot 的帮助下&#xff0c;可以大幅提高界面的开发效率。 主要特色&#xff1a; 真实的 UI 效果。可以设置主题&#xff0c;方便查看在不同主题下界面的效果。可以设置语言&#xf…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...