c++如何让函数在main()之前或之后运行

对于编程人员来讲,main 函数是程序的入口,但事实上 main 函数之前也发生了很多操作。在 main 函数开始前,分成两部分 “系统调用部分” 和 “C++ 程序自身的部分”

main() 执行前

  1. 入口函数对运行库和程序运行环镜进行初始化,包括 堆、I/O、线程、全局变量构造等等。
  2. 入口函数完成初始化后,调用 main 函数,正式开始执行程序主体部分。

main函数执行之前,主要就是初始化系统相关资源:
1.设置栈指针
2.初始化static静态和global全局变量,即data段的内容
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容
4.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数

main运行前可运行哪些代码

1.全局对象的构造函数会在 main 函数之前执行。

比如:MFC里面的 C**App类的theApp对象,其执行顺序就在main函数之前
在main函数之前声明一个类的全局的对象。
那么其执行顺序,根据全局对象的生存期和作用域,肯定先于main函数

class simpleClass
{
public:
       simpleClass( )
       {
              cout << "simpleClass constructor.." << endl;  //step2
       }
};
 
 
simpleClass g_objectSimple;         //step1全局对象
// 这里调用了全局对象的构造函数
 
int _tmain(int argc, _TCHAR* argv[])  //step3
{
       return 0;
}

可单步调试查看执行顺序为step1、step2、step3。

2. 全局变量、对象和静态变量、对象的空间分配和赋初值

发生在执行main函数之前,而main函数执行完后,
还要去执行一些诸如释放空间、释放资源使用权等操作

class simpleClass
{
public:
       simpleClass( )
       {
              cout << "simpleClass constructor.." << endl;       //step2 
       }
};
 
class simpleClassTwo
{
public:
       static simpleClass m_sSimpleClass;
};
 
simpleClass simpleClassTwo::m_sSimpleClass = simpleClass(); //step1 静态对象
 
int _tmain(int argc, _TCHAR* argv[])                        //step3
 
{
        return 0;
}

可单步调试查看执行顺序为step1、step2、step3。

全局变量的赋值函数

#include <iostream>
using namespace std;

int f(){
    printf("before");
    return 0;
}

int _ = f();

int main(){
    return 0;
}

全局lambda变量调用

int a = []() {
    std::cout << "a";
    return 0;
}();

int main() {
    std::cout << "b";
    return 0;
}

3. 进程启动后,要执行一些初始化代码

(如设置环境变量等),然后跳转到main执行。全局对象的构造也在main之前。

在写程序时,比如一个模块,通常要有 initialize 和 de-initialize,但是我们写 C 程序的时候为什么有些模块没有这两个过程么呢?比如我们程序从 main 开始就可以 malloc,free,但是我们在 main 里面却没有初始化堆。再比如在 main 里面可以直接 printf,可是我们并没有打开标准输出文件啊。

操作系统装载程序之后,首先运行的代码并不是main的第一行,而是某些特别的代码,这些代码准备好main函数执行说需要的环境,并且负责调用main函数,这时候你才可以再main函数里放心大胆的写各种代码:申请内存、使用系统调用、触发异常、访问IO。在main函数返回之后,他会记录main函数的返回值,调用atexit注册的函数,然后结束进程。
——《程序员的自我修养–链接、装载与库》

那main() 执行后呢?

main函数执行完毕后,返回到入口函数,入口函数进行清理工作,包括全局变量的析构、堆销毁、关闭I/O等,然后系统调用结束进程。

main函数结束可以通过 return 0;或者 exit(0) 来结束,此时程序并非直接结束,而是先调用一些终止处理程序然后再结束。可以使用int atexit(void (*func)(void));来追加自定义终止处理程序,终止处理程序由 exit函数自动调用,调用顺序与登记顺序相反。

如果main函数发生了异常或者使用_exit和_Exit来退出程序,则不会调用终止处理程序。

微信的mars库中对运行在main前和main后的函数封装方法

运行前用全局变量和运行后用atexit函数,
使用BOOT_RUN_STARTUP的函数,在main运行前调用
使用BOOT_RUN_EXIT的函数,在main运行后调用

#ifdef __cplusplus
extern "C" {
#endif

__inline int boot_run_atstartup(void (*func)(void)) { func(); return 0;}
__inline int boot_run_atexit(void (*func)(void)) { return atexit(func);}

#ifdef __cplusplus
}
#endif

#define BOOT_RUN_STARTUP(func) VARIABLE_IS_NOT_USED static int __anonymous_run_variable_startup_##func = boot_run_atstartup(func)
#define BOOT_RUN_EXIT(func) VARIABLE_IS_NOT_USED static int __anonymous_run_variable_exit_##func = boot_run_atexit(func)

使用全局变量和atexit实现函数在main运行前和运行后运行

#include <QCoreApplication>
#include <QtDebug>

class Tmp {
public:
    Tmp() {
        qDebug() << Q_FUNC_INFO;
    }
    ~Tmp() {
        qDebug() << Q_FUNC_INFO;
    }
};

int main_before() {
    qDebug() << Q_FUNC_INFO;
    return 0;
}

void main_after() {
    qDebug() << Q_FUNC_INFO;
}

int doExit(void (*func)(void)) {
    return atexit(func);
}

int nBefore = main_before();
int nAfter = doExit(main_after);
Tmp oTmp;

int main(int argc, char *argv[])
{
    qDebug() << Q_FUNC_INFO;
//    QCoreApplication app(argc, argv);
//    return app.exec(); // 进入qt的事件循环
    return 0;
}
/* 输出
int main_before()
Tmp::Tmp()
int main(int, char**)
Tmp::~Tmp()
void main_after()
*/

4. 通过关键字__attribute__

让一个函数在主函数之前运行,进行一些数据初始化、模块加载验证等。

如果是GNUC的编译器(gcc,clang),就在你要执行的方法前加上 attribute((constructor))

#include<stdio.h>

__attribute__((constructor)) void func()
{
    printf("hello world\n");
}

int main()
{
    printf("main\n"); //从运行结果来看,并没有执行main函数
}

同理,如果想要在main函数结束之后运行,
可加上__attribute__((destructor))

#include<stdio.h>

void func()
{
    printf("hello world\n");
    //exit(0);
    return 0;
}

__attribute__((constructor))void before()
{
    printf("before\n");
    func();
}


__attribute__((destructor))void after()
{
    printf("after\n");

}

int main()
{
    printf("main\n"); //从运行结果来看,并没有执行main函数
}

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值