atexit()的原型
atexit的函数原型如下:可以看出它是一个函数指针,里面存放的是函数的地址,当调用此函数时无须传递任何参数,该参数也不能有返回值。
int atexit( void ( __cdecl *func )( void ) );
1
intatexit(void(__cdecl *func)(void));
atexit()的作用
在标准库中有这样的描述:
The atexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to atexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to atexit cannot take parameters. atexit and _onexit use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.
1
Theatexitfunctionispassedtheaddressofafunction(func)tobecalledwhentheprogramterminatesnormally.SuccessivecallstoatexitcreatearegisteroffunctionsthatareexecutedinLIFO(last-in-first-out)order.Thefunctionspassedtoatexitcannottakeparameters.atexitand_onexitusetheheaptoholdtheregisteroffunctions.Thus,thenumberoffunctionsthatcanberegisteredislimitedonlybyheapmemory.
翻译过来的意思就是:当程序正常终止时,atexit函数传递要调用的函数(func)的地址。 对atexit的连续调用创建一个在LIFO(先进先出)命令中执行的功能寄存器。 传递给atexit的函数不能有参数。 atexit和_onexit使用堆来保存函数的寄存器。 因此,可以注册的功能数量仅受堆存储器限制。
atexit()的调用次序
#include
#include
void func1(void)
{
printf("func1()\n");
}
void func2(void)
{
printf("func2()\n");
}
void func3(void)
{
printf("func3()\n");
}
int main()
{
atexit(func1);
atexit(func2);
atexit(func3);
printf("main\n");
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include
#include
voidfunc1(void)
{
printf("func1()\n");
}
voidfunc2(void)
{
printf("func2()\n");
}
voidfunc3(void)
{
printf("func3()\n");
}
intmain()
{
atexit(func1);
atexit(func2);
atexit(func3);
printf("main\n");
return0;
}
你会发现,首先调用的是main,说明atexit是在进程退出的时候,调用曾经注册过的函数,即atexit在退出前会进行注册,退出时进行回调。
atexit可以注册多个函数,调用多个函数时,它的调用顺序并不是调用次序,而是压栈次序,即先进后出。如果一个函数被多次登记,也会被多次调用。
atexit()注册限制
按照ISO C的规定,一个进程可以登记32个函数,这些函数由exit自动调用,通常这32个函数被称为终止处理程序,并调用atexit函数来登记这些函数。
下面我们验证一下,看是否有限制,我们沿用上述程序,注册35个函数:
func35()func34()func33()func32()func31()func30()func29()func28()func27()func26()
func25()func24()func23()func22()func21()func20()func19()func18()func17()func16()
func15()func14()func13()func12()func11()func10()func9()func8()func7()func6()
func5()func4()func3()func2()func1()
1
2
3
4
func35()func34()func33()func32()func31()func30()func29()func28()func27()func26()
func25()func24()func23()func22()func21()func20()func19()func18()func17()func16()
func15()func14()func13()func12()func11()func10()func9()func8()func7()func6()
func5()func4()func3()func2()func1()
其实是可以注册成功的。atexit()所能注册的函数是受堆寄存器唯一控制的,并不是一成不变的。