多玩YY语音的面试题:C++中如何在main()函数之前执行操作?
第一反应main()函数是所有函数执行的开始。但是问题是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。
考虑到全局对象,同理会进一步思考静态对象的作用域。将上述示例进一步扩展如下:
- 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。
至此,我们可以总结出:定义在main( )函数之前的全局对象、静态对象的构造函数在main( )函数之前执行。
再进一步思考,既然可以在main( )函数之前执行全局、静态对象的构造函数。那么有没有函数在main( )函数之后执行呢?
有的,onexit函数。原型如下:
_onexit_t _onexit(
_onexit_t function
);
_onexit_t_m _onexit_m(
_onexit_t_m function
);
解释:The _onexit function is passed the address of a function (function) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.
核心点:
1) 执行期——程序执行终止的时候;
2) 传递参数——函数的地址,即函数指针;
3) 执行顺序——后进先出。
_onexit is a Microsoft extension. For ANSI portability, use atexit. The _onexit_m version of the function is for mixed mode use.
onexit是微软的扩展版本,标准C++里面应用的是atexit。
【MSDN】示例:
- <span style="font-size:14px;">#include <stdlib.h>
- #include <stdio.h>
- /* Prototypes */
- int fn1(void), fn2(void), fn3(void), fn4 (void);
- int main( void )
- {
- _onexit( fn1 );
- _onexit( fn2 );
- _onexit( fn3 );
- _onexit( fn4 );
- printf( "This is executed first.\n" );
- }
- int fn1()
- {
- printf( "next.\n" );
- return 0;
- }
- int fn2()
- {
- printf( "executed " );
- return 0;
- }
- int fn3()
- {
- printf( "is " );
- return 0;
- }
- int fn4()
- {
- printf( "This " );
- return 0;
- }
执行结果如下:
显然,读程序可以看出main( )函数执行完毕后又执行了onexit( )函数。
还有没有其他特殊的情况呢?持续探讨、更新中……
2013-4-18
- 上一篇:模块化动态划线实现解读
-
15楼
wojiushiwo987 2小时前发表 [回复]
-
谢谢提醒,一些知识点涉猎的不够全面,我会尽快更新上。
-
13楼
smile588477 昨天 14:39发表 [回复]
- 学习一下
-
12楼
0c0c0f 昨天 09:07发表 [回复]
-
获取指向新进程的完整命令行指针
获取指向新进程环境变量的指针
初始化c/c++运行库的全局变量。
初始化c运行库内存分配函数(malloc和calloc)和其他底层i/o
-
10楼
pl___ 昨天 02:37发表 [回复]
-
C++中如何在main()函数之前执行操作?
不提倡使用全局变量. 全局变量会有副作用(比如初始化顺序相关的,又比如异常相关的,调试困难,等).
正确的方法是在编译选项里指定一个特殊的函数作为入口点.
更正确的方法是不要依赖全局初始化.
在用的时候多写一行init()或者用构造函数(注意:不要用全局变量)
-
8楼
苍穹浪 昨天 23:36发表 [回复]
-
ISO/IEC C++ N3485
3.6.2 Initialization of non-local variables [basic.start.init]
4 It is implementation-defined whether the dynamic initialization of a non-local variable with static storage
duration is done before the first statement of main. If the initialization is deferred to some point in time
after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable
defined in the same translation unit as the variable to be initialized.34
注意最后一句,C++标准仅规定非本地变量会在所在的编译单元被调用前初始化,并不保证main前初始化。这种方法在main前执行代码的方式需要依赖编译器实现,不具有可移植性。
-
7楼
wojiushiwo987 前天 21:11发表 [回复]
-
静态对象又分为:局部静态对象和全局静态对象。全局对象和全局静态对象先于main()函数构造,所以执行靠前!
-
6楼
hubingfeng0803 前天 16:49发表 [回复]
- 分析的好!
-
2楼
wojiushiwo987 前天 23:14发表 [回复]
-
谢谢回复。析构函数主要是指当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。确切的说其和main()函数关系不大。