C/C++程序在main之前执行代码
来源:《周哥教IT.C语言深学活用》https://ke.qq.com/course/242707#tuin=a71606
我们在学习C/C++语言的时候,通常认为main函数是整个程序执行的开始。实际上,在main函数之前,会有一系列初始化的操作,这样的操作通常是由链接器等完成的。具体说来,程序最早执行的函数其实并不是main,在windows中,是mainCRTStartup,这个函数是链接器执行以初始化运行时库的,此函数又会调用CRTInit函数,该函数会对C全局变量、C内存分配以及C++中的全局类对象和构造函数进行初始化工作。所以想要在main函数之前执行一些自己的代码,是有可能的。
1. Linux环境下利用gcc的__attribute关键字
在Linux环境的C编程中,可以利用__attribute关键字定义constructor和destructor,其中前者会在main函数之前执行,后者会在main函数之后执行。
代码如下:
#include <stdio.h>
__attribute((constructor)) void before_main()
{
printf("before main!\n");
}
__attribute((destructor)) void after_main()
{
printf("after main!\n");
}
int main(void)
{
printf("This is main function.\n");
;
}
before_main.c
运行结果:
natalie@ubuntu:~/Desktop/zhou_it_c/before_main$ gcc before_main.c -o before_main
natalie@ubuntu:~/Desktop/zhou_it_c/before_main$ ./before_main
before main!
This is main function.
after main!
2. Windows环境下利用#pragma预定义
上面我们说过CRTInit函数中会做一些初始化工作,包括C库、C的初始化函数、C++库、C++的初始化函数等。C和C++分别有一张表来保存初始化函数指针,每个表又会使用2个指针来明确范围。在初始化过程中,__CRTInit函数会一次调用这两个表中的函数,所以如果我们能把要执行的函数放在这两个表中,那么就可以达到在main之前执行代码的目的了。
C初始化函数表的范围是:[ __xi_a, __xi_a ] C++初始化函数表的范围是:[ __xc_a, __xc_z]
我们在具体执行的时候,通过定义特殊的段名称“.CRT$XIU”和“.CRT$XCU”,把要执行的函数放在段中。链接器就会形成日下的C初始化函数表:
[__xi_a, ..., before1(xiu), ..., __xi_z]
以及C++初始化函数表:
[__xc_a, ..., before2(xcu), ..., __xc_z]
代码如下:
#include <stdio.h>
int before_main(void)
{
printf("before main!\n");
;
}
typedef int func();
#pragma data_seg(".CRT$XIU")
static func *before[] = { before_main };
#pragma data_seg()
int main(void)
{
printf("This is main function.\n");
;
}
before_main.c
3. C++编程中利用定义全局类对象or全局变量
mainCRTStartup会对全局对象a初始化,也就是说a的构造含税会先于main执行,所以只需要在a的构造函数中定义我们要执行的函数。
另一种方式是定义一个全局变量为函数运行后的结构,那么该函数就会用于初始化,会先于main执行。
代码如下:
#include <iostream>
using namespace std;
using std::cout;
int func()
{
cout <<"before main: func()" << endl;
;
}
class A
{
public:
A()
{
cout << "A() constructor" << endl;
}
~A()
{
cout << "A() destructor" << endl;
}
};
A a;
int g_iValue = func();
int main(void)
{
cout << "This is main function." << endl;
;
}
before_main.cpp
运行结果:
A() constructor
before main: func()
This is main function.
A() destructor
C/C++程序在main之前执行代码的更多相关文章
- 编写Java程序,观察类启动时静态代码块和main()的执行顺序
返回本章节 返回作业目录 需求说明: 观察类启动时静态代码块和main()的执行顺序 在Book类中定义静态代码块. 在Book中分别定义一个普通实例方法和静态方法. 在Book类的静态代码块中调用静 ...
- main函数执行前、后再执行的代码
一.main结束 不代表整个进程结束 (1)全局对象的构造函数会在main 函数之前执行, 全局对象的析构函数会在main函数之后执行: 用atexit注册的函数 ...
- C 语言main 函数终极探秘(&& 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行)
所有的C程序必须定义一个称之为main的外部函数,这个函数是程序的入口,也就是当程序启动时所执行的第一个函数,当这个函数返回时,程序也将终止,并且这个函数的返回值被看成是程序成功或失败的 ...
- c/c++ main函数执行之前/后
转载自:http://bbs.csdn.net/topics/300103318#r_78088969 main函数之前--真正的函数执行入口或开始 一种解释: 实际上,在可执行文件被加载之后,控制权 ...
- (转)Java程序利用main函数中args参数实现参数的传递
Java程序利用main函数中args参数实现参数的传递 1.运行Java程序的同时,可以通过输入参数给main函数中的接收参数数组args[],供程序内部使用!即当你在Java命令行后面带上参数,J ...
- [学习笔记]java基础Java8SE开发环境搭建、第一个Java Hello World、Java程序的编译与执行
本文作者:sushengmiyan 本文地址:http://blog.csdn.net/sushengmiyan/article/details/25745945 内容简介: ------------ ...
- 如何用C#动态编译、执行代码
在开始之前,先熟悉几个类及部分属性.方法:CSharpCodeProvider.ICodeCompiler.CompilerParameters.CompilerResults.Assembly. 一 ...
- [转]如何用C#动态编译、执行代码
在开始之前,先熟悉几个类及部分属性.方法:CSharpCodeProvider.ICodeCompiler.CompilerParameters.CompilerResults.Assembly. 一 ...
- C#动态执行代码
在开始之前,先熟悉几个类及部分属性.方法:CSharpCodeProvider.ICodeCompiler.CompilerParameters.CompilerResults.Assem ...
随机推荐
- PHP常用字符串处理函数
(1)strlen(string) 返回字符串长度 (2)strpos(string,find,begin) 返回find字符串第一次出现的位置(从0开始) string:处理的字符串 find:想找 ...
- Sql语句varchar或nvarchar字段条件前加N的性能差异
Sql语句varchar或nvarchar字段条件前加N的话是对这个字段进行Unicode编码, 这样做的目的是避免在这种字段中存入俄文.韩文.日文的情况下有可能会出现乱码. 但这样做也会有性能问题, ...
- python 发送邮件,未完
def send_mail(): try: print "send mail..." # handle = smtplib.SMTP('smtp.163.com', 25) # h ...
- Weave Scope 容器地图 - 每天5分钟玩转 Docker 容器技术(80)
Weave Scope 的最大特点是会自动生成一张 Docker 容器地图,让我们能够直观地理解.监控和控制容器.千言万语不及一张图,先感受一下. 下面开始实践 Weave Scope. 安装 执行如 ...
- KM算法的应用
HDU2255 模板 难度x HDU2282 思维 难度XXx HDU3722 模板 难度X HDU3395 模版 HDU1533 最小值模型 难度x HDU2853 HDU3 ...
- ZOJ2345Gold Coins 简单分块
昨天做过一样的题: 平方和公式:n*(n+1)*(2n+1) #include<cstdio> #include<cstdlib> #include<iostream&g ...
- Java面向对象 集合(上)
Java面向对象 集合(上) 知识概要: (1)体系概述 (2)共性方法 (3)迭代器 (4)list集合 (5)Set 集合 体系概述: 集 ...
- 由String的构造方法引申出来的java字符编码
在String类的constructors中,有一个constructor是将int数组类型转化为字符串: int[] num = {48,49,50,51,52}; String numStr = ...
- JAVA提高五:注解Annotation
今天我们学习JDK5.0中一个非常重要的特性,叫做注解.是现在非常流行的一种方式,可以说因为配置XML 比较麻烦或者比容易查找出错误,现在越来越多的框架开始支持注解方式,比如注明的Spring 框架, ...
- (10.19)Java小作业
在java的学习过程中数组的版块也是十分重要的,包括一些教程也会在这个知识点花上更多的时间来讲解,足以证明 这个知识点的重要性,今天想和大家分享一道学习数组过程中不可避免的求最值题. 已知一个整形数组 ...