Chinaunix

标题: atexit()问题~ [打印本页]

作者: 单眼皮大姐    时间: 2010-07-05 23:11
标题: atexit()问题~
哪位大侠帮忙解释下 atexit()函数是在main()结束前执行呢还是在结束之后执行呢???
作者: 没本    时间: 2010-07-05 23:54
man 3 exit
作者: 没本    时间: 2010-07-06 00:05
本帖最后由 没本 于 2010-07-06 00:36 编辑

如果你又问:那么exit()是在main()之后执行的么?
我只能建议你做如下实验:

  1. $ echo "int main(){return 0;}" > test.c
  2. $ gcc -g -o test test.c
  3. $ gdb test
  4. GNU gdb (GDB) 7.1
  5. Copyright (C) 2010 Free Software Foundation, Inc.
  6. License GPLv3+: GNU GPL version 3 or later <[url]http://gnu.org/licenses/gpl.html[/url]>
  7. This is free software: you are free to change and redistribute it.
  8. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
  9. and "show warranty" for details.
  10. This GDB was configured as "i686-pc-linux-gnu".
  11. For bug reporting instructions, please see:
  12. <[url]http://www.gnu.org/software/gdb/bugs/[/url]>...
  13. Reading symbols from /home/foo/tmp/test...done.
  14. (gdb) b exit
  15. Function "exit" not defined.
  16. Make breakpoint pending on future shared library load? (y or [n]) y

  17. Breakpoint 1 (exit) pending.
  18. (gdb) b main
  19. Breakpoint 2 at 0x8048377: file test.c, line 1.
  20. (gdb) r
  21. Starting program: /home/foo/tmp/test

  22. Breakpoint 2, main () at test.c:1
  23. 1       int main(){return 0;}
  24. (gdb) n
  25. 0xb7e95c76 in __libc_start_main () from /lib/libc.so.6
  26. (gdb) c
  27. Continuing.

  28. Breakpoint 1, 0xb7eace14 in exit () from /lib/libc.so.6
  29. (gdb) c
  30. Continuing.

  31. Program exited normally.
  32. (gdb)
复制代码
相信科学,远离邪+教。
作者: 没本    时间: 2010-07-06 00:07
另一佐证:
__libc_start_main

Name

__libc_start_main -- initialization routine
Synopsis

int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end));

Description

The __libc_start_main() function shall perform any necessary initialization of the execution environment, call the main function with appropriate arguments, and handle the return from main(). If the main() function returns, the return value shall be passed to the exit() function.

Note: While this specification is intended to be implementation independent, process and library initialization may include:

performing any necessary security checks if the effective user ID is not the same as the real user ID.

initialize the threading subsystem.

registering the rtld_fini to release resources when this dynamic shared object exits (or is unloaded).

registering the fini handler to run at program exit.

calling the initializer function (*init)().

calling main() with appropriate arguments.

calling exit() with the return value from main().

This list is an example only.
__libc_start_main() is not in the source standard; it is only in the binary standard.

See Also

The section on Process Initialization in each of the architecture specific supplements.
作者: OwnWaterloo    时间: 2010-07-06 00:10
理论上说:

1. 标准要求main返回等效于调用exit
c99 5.1.2.2.3 Program termination

2. exit首先会调用atexit注册的函数
c99 7.20.4.3 The exit function


从实践出发:

1. 可以写个程序大致猜测

  1. #include <stdlib.h>
  2. int main() {
  3.       struct local {
  4.             ~local() { printf("before return\n"); }
  5.       static void onexit() { printf("in atexit\n"); }
  6.       } l;
  7.       atexit(&local::onexit);
  8.       return 0;
  9. }
复制代码
2. 查看进程启动代码

进程、线程的启动代码都是如下形式:

  1. exit( main( argc, argv ) );
  2. _endthreadex( thread_routine(arg) );
复制代码
这是如何保证main返回等效于调用exit的方法。
这里可以看出, exit是在main返回之后, 以main的返回值来调用。
从这里也可以看出, 最好是让main或者线程函数返回到它们的caller, 然后由caller余下部分的代码调用exit或者_endthreadex。

如果直接调用exit或_endthreadex, 从调用点到这个启动main或线程的caller之间的frame的清理工作就不会被执行。
作者: pmerofc    时间: 2010-07-06 06:12
提示: 作者被禁止或删除 内容自动屏蔽
作者: OwnWaterloo    时间: 2010-07-06 07:24
回复 6# pmerofc

这不矛盾。

"main返回等效于以main的返回值调用exit"是有前提的。
违反这个前提条件, 结束状态就是unspecified。

而void main显然违反这个前提条件……

c99 5.1.2.2.3 Program termination
——依然是这里

If the return type of the main function is a type compatible with int, a return from the
initial call to the main function is equivalent to calling the exit function with the value
returned by the main function as its argument;10)

——前提在黑体中

reaching the } that terminates the main function returns a value of 0.

——这是C99新加的, 和C++兼容。

If the return type is not compatible with int,
the termination status returned to the host environment is unspecified.

——void main属于这一类。

作者: 单眼皮大姐    时间: 2010-07-06 10:48
回复 3# 没本


    谢谢了~~~~~呵呵,明白啦~~~
作者: 单眼皮大姐    时间: 2010-07-06 11:02
回复 5# OwnWaterloo


    谢谢阿~~~~明白啦~~呵呵
作者: pmerofc    时间: 2010-07-06 17:39
提示: 作者被禁止或删除 内容自动屏蔽
作者: pandaiam    时间: 2010-07-06 17:41
上次争论不是说在main之后运行么。
作者: OwnWaterloo    时间: 2010-07-06 18:54
回复 10# pmerofc

exit和_endthreadex这种函数是不会返回的啦。

  1. process_startup( ... ) {
  2. exit( main(argc, argv) );
  3. // 不会执行到这里
  4. }
复制代码

  1. thread_startup( ... ) {
  2. _endthreadex( thread_routine(arg) );
  3. // 也不会执行到这里
  4. }
复制代码
pthread是标准, linux我不懂。
Windows的话, _endthreadex当中会调用ExitThread。
ExitThread就真的结束线程, OS不会再给它时间片, 线程不能够继续执行代码
不会返回到_endthreadex,也不会返回到thread_startup。
等着返回值被取出并关闭后(GetExitCode/Wait join)线程就完全撤消了。

exit也类似, 不过要做的事情更多一些。


无论是在什么地方调用exit/_endthreadex/ExitProcess/ExitThread, 就不会再返回到调用点上了。
main返回前如果调用了exit, main就不会返回, process_startup中的exit就不会被调用。
作者: pmerofc    时间: 2010-07-07 18:11
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2