当前位置: 首页 > 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…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...