【转】如何在main函数之前和之后执行一段程序

转自:https://blog.csdn.net/mlyhzt/article/details/111351883


C/C++
要想在main函数之前或之后运行一段代码,就得清楚在main函数执行之前程序都会干些啥,main函数执行之后又会干些啥?

main函数
main函数,又称主函数,是程序执行的起点。
每个c/c++代码都有一个main函数,程序启动后,会开启一个主线程执行main函数,在main函数内部我们可以开启很多线程,如果主函数main,return的话,这些在main函数里开启的线程都会结束。(这是大方向上可以这样讲)
其实,在程序运行之前,首先运行的代码并不是main的第一行,而是某些特别的代码,这些代码准备好main函数执行所需要的环境,并且负责调用main函数,这时你才可以在main函数里放心大胆的写各种代码:申请内存、使用系统调用、触发异常、访问IO。在main函数返回之后,他会记录main函数的返回值,调用atexit注册的函数,然后结束进程。
-main函数前:
程序在执行时会调用各种各样的运行时库函数,因此执行前main函数必须要初始化好运行时库,还要完成一些全局变量以及C内存分配等初始化工作,在C++里,还要执行全局类对象的构造函数。最后才调用main函数。
所以我们可以根据这些特点来进行。
法一:C/C++方法
利用全局变量的构造函数初始化的时候可以被执行的特点来进行。

#include<iostream>
using namespace std;

class A
{
public:
	A(){cout<<"A"<<endl;}//构造函数
};
A a;//声明一个全局变量

int main()
{
	cout<<"main func"<<endl;
	return 0;
}

运行结果:
在这里插入图片描述
法二:C++方法
全局变量的赋值函数,会在main之前执行。(C中好像不允许通过函数给全局变量赋值)

#include<iostream>
#include<stdio.h>
using namespace std;

int f()
{
	printf("before\n");
	return 0;
}
int a = f();
int main()
{
	printf("main\n");
	return 0;
}

运行结果:
在这里插入图片描述
法三:如果是GNUC的编译器,可在你要执行的方法前加__attribute__((constructor))

#include<stdio.h>

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

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

本方法参考网上方法,本人的编译器可能和所说的不一样,没有运行出来
-main函数后:

在main函数返回之后,系统会记录main函数的返回值,调用atexit注册的函数,然后结束进程。
法一:C/C++方法
利用析构函数的特点

#include<iostream>
using namespace std;

class A
{
public:
	~A()
	{
		cout<<"~A"<<endl;
	}
};

A a;
int main()
{
	cout<<"main"<<endl;
	return 0;
}

运行结果:
在这里插入图片描述
法二:如果是GNUC的编译器,可在你要执行的方法前加__attribute__((destructor))

#include<stdio.h>

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

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

int main()
{
	printf("main\n");
}

法三:C/C++
onexit(func) 对于C 或 atexit(func) 对于C++

#include<iostream>
using namespace std;

int func1(void)
{
    cout << "function 1" << endl;
	return 0;
}
void func2(void)
{
    cout << "function 2" << endl;
}
int main()
{
	printf("hh\n");
	onexit(func1);
    atexit(func2);
	printf("hh\n");
    return 0;
}


运行结果:
在这里插入图片描述
onexit(func) 要求注册的函数func返回值为int型;
atexit(func)要求函数没有返回值,即返回值类型为void;
不过这两个函数都要求函数没有传入参数。
注意:onexit和atexit可以混用,但是注册函数时,是一个入栈的过程,执行是出栈。因此如上代码最后输出应该是先输出“fuction 2”,然后是“fuction 1”。析构函数在onexit和atexit注册的函数执行之后执行。

注意:
1、这里对atexit函数进行一些解释
很多时候我们需要在程序退出的时候做一些诸如释放资源的操作,但程序退出的方式有很多,比如main()函数运行结束、在程序的某个
地方用exit()结束程序、用户通过Ctrl+C等操作来终止程序等等,因此需要一种与程序退出方式无关的方法来进行程序退出时的必要处理。
方法就是用atexit()函数来注册程序正常终止时要被调用的函数。
atexit()函数的参数时一个函数指针,函数指针指向一个没有参数也没有返回值的函数。它注册一个函数,使得调用exit时或函数
main返回时会调用这个函数,如果注册成功,则atexit函数返回0,否则返回非0值。所有向atexit函数注册的函数按与注册相反的顺序调用,然后再由atexit函数完成所有标准清理操作。
atexit()函数原型是;int atexit(void(*)(void));
2、attribute((constructor))应该是在main函数之前,执行一个函数,便于我们做一些准备工作。
constructor参数让系统执行main()函数之前调用函数(被
arrribute((constructor))修饰的函数)。同理,destructor让系统在main()函数调用了exit()之后,调用我们的函数,带有
这些修饰属性的函数,对于我们初始化一些在程序中使用的数据非常有用。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值