欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C/C++启动函数

程序员文章站 2023-10-24 17:25:51
今天在看《windows核心》第四章,其中我感兴趣的是关于启动函数的描述。 启动函数的用途如下: 1,获取指向新进程的完整命令行的一个指针; 2,获取指向新进程的环境变量的一...
今天在看《windows核心》第四章,其中我感兴趣的是关于启动函数的描述。
启动函数的用途如下:
1,获取指向新进程的完整命令行的一个指针;
2,获取指向新进程的环境变量的一个指针;
3,初始化c/c++运行库的全局变量
4,初始化所有全局和静态c++类对象的构造函数。
对于一个程序而言,在执行main函数之前会执行crtexe.c文件中maincrtstartup或wmaincrtstartup函数,如下所示:
[html]
<span style="font-size:18px;">#ifdef wprflag 
int wmaincrtstartup( 
#else  /* wprflag */ 
int maincrtstartup( 
#endif  /* wprflag */ 
 
#endif  /* _winmain_ */ 
        void 
        ) 

        /* 
         * the /gs security cookie must be initialized before any exception 
         * handling targetting the current image is registered.  no function 
         * using exception handling can be called in the current image until 
         * after __security_init_cookie has been called. 
         */ 
        __security_init_cookie(); 
 
        return __tmaincrtstartup(); 
}</span> 
__tmaincrtstartup函数如下所示:
[html]
<span style="font-size:18px;">__declspec(noinline) 
int 
__tmaincrtstartup( 
        void 
        ) 

#ifdef _winmain_ 
        _tuchar *lpszcommandline; 
        startupinfo startupinfo; 
        bool indoublequote=false; 
 
        __try { 
                        /* 
                        note: msdn specifically notes that getstartupinfo returns no error, and throws unspecified seh if it fails, so 
                        the very general exception handler below is appropriate 
                        */ 
            getstartupinfo( &startupinfo ); 
        } __except(exception_execute_handler) { 
            return 255; 
        } 
#endif  /* _winmain_ */ 
 
 
        /* 
         * guard the initialization code and the call to user's main, or 
         * winmain, function in a __try/__except statement. 
         */ 
 
        __try 
        { 
            /* 
             * there is a possiblity that the module where this object is 
             * linked into is a mixed module. in all the cases we gurantee that 
             * native initialization will occur before managed initialization. 
             * also in anycase this code should never be called when some other 
             * code is initializing native code, that's why we exit in that case. 
             * 
             * do runtime startup initializers. 
             * 
             * note: the only possible entry we'll be executing here is for 
             * __lconv_init, pulled in from charmax.obj only if the exe was 
             * compiled with -j.  all other .crt$xi* initializers are only 
             * run as part of the crt itself, and so for the crt dll model 
             * are not found in the exe.  for that reason, we call _initterm, 
             * not _initterm_e, because __lconv_init will never return failure, 
             * and _initterm_e is not exported from the crt dll. 
             * 
             * note further that, when using the crt dll, executing the 
             * .crt$xi* initializers is only done for an exe, not for a dll 
             * using the crt dll.  that is to make sure the -j setting for 
             * the exe is not overriden by that of any dll. 
             */ 
            void *lock_free=0; 
            void *fiberid=((pnt_tib)ntcurrentteb())->stackbase; 
            int nested=false; 
            while((lock_free=interlockedcompareexchangepointer((volatile pvoid *)&__native_startup_lock, fiberid, 0))!=0) 
            { 
                if(lock_free==fiberid) 
                { 
                    nested=true; 
                    break; 
                } 
 
                /* some other thread is running native startup/shutdown during a cctor/domain unload. 
                    should only happen if this dll was built using the everett-compat loader lock fix in clrit.h 
                */ 
                /* wait for the other thread to complete init before we return */ 
                sleep(1000); 
            } 
 
            if (__native_startup_state == __initializing) 
            { 
                _amsg_exit( _rt_crt_init_conflict); 
            } 
            else if (__native_startup_state == __uninitialized) 
            { 
                __native_startup_state = __initializing; 
#ifndef _syscrt 
                if (_initterm_e( __xi_a, __xi_z ) != 0) 
                { 
                    return 255; 
                } 
#else  /* _syscrt */ 
                _initterm((_pvfv *)(void *)__xi_a, (_pvfv *)(void *)__xi_z); 
#endif  /* _syscrt */ 
            } 
            else 
            { 
                has_cctor = 1; 
            } 
 
            /* 
            * do c++ constructors (initializers) specific to this exe 
            */ 
            if (__native_startup_state == __initializing) 
            { 
                _initterm( __xc_a, __xc_z ); 
                __native_startup_state = __initialized; 
            } 
            _asserte(__native_startup_state == __initialized); 
            if(!nested) 
            { 
                /* for x86, the definition of interlockedexchangepointer wrongly causes warning c4312 */ 
#pragma warning(push) 
#pragma warning(disable:4312) 
                interlockedexchangepointer((volatile pvoid *)&__native_startup_lock, 0); 
#pragma warning(pop) 
            } 
 
            /* 
             * if we have any dynamically initialized __declspec(thread) 
             * variables, then invoke their initialization for the primary 
             * thread used to start the process, by calling __dyn_tls_init 
             * through a callback defined in tlsdyn.obj. 
             */ 
            if (__dyn_tls_init_callback != null && 
                _isnonwritableincurrentimage((pbyte)&__dyn_tls_init_callback)) 
            { 
                __dyn_tls_init_callback(null, dll_thread_attach, null); 
            } 
 
            /* enable buffer count checking if linking against static lib */ 
            _crtsetcheckcount(true); 
 
#ifdef _winmain_ 
            /* 
             * skip past program name (first token in command line). 
             * check for and handle quoted program name. 
             */ 
#ifdef wprflag 
            /* os may not support "w" flavors */ 
            if (_wcmdln == null) 
                return 255; 
            lpszcommandline = (wchar_t *)_wcmdln; 
#else  /* wprflag */ 
            lpszcommandline = (unsigned char *)_acmdln; 
#endif  /* wprflag */ 
 
            while (*lpszcommandline > spacechar || 
                   (*lpszcommandline&&indoublequote)) { 
                /* 
                 * flip the count from 1 to 0 or 0 to 1 if current character 
                 * is doublequote 
                 */ 
                if (*lpszcommandline==dquotechar) indoublequote=!indoublequote; 
#ifdef _mbcs 
                if (_ismbblead(*lpszcommandline)) { 
                    if (lpszcommandline) { 
                        lpszcommandline++; 
                    } 
                } 
#endif  /* _mbcs */ 
                ++lpszcommandline; 
            } 
 
            /* 
             * skip past any white space preceeding the second token. 
             */ 
            while (*lpszcommandline && (*lpszcommandline <= spacechar)) { 
                lpszcommandline++; 
            } 
 
#ifdef wprflag 
            mainret = wwinmain( 
#else  /* wprflag */ 
            mainret = winmain( 
#endif  /* wprflag */ 
                       (hinstance)&__imagebase, 
                       null, 
                       lpszcommandline, 
                       startupinfo.dwflags & startf_useshowwindow 
                        ? startupinfo.wshowwindow 
                        : sw_showdefault 
                      ); 
#else  /* _winmain_ */ 
 
#ifdef wprflag 
            __winitenv = envp; 
            mainret = wmain(argc, argv, envp); 
#else  /* wprflag */ 
            __initenv = envp; 
            mainmainret = main(argc, argv, envp); 
#endif  /* wprflag */ 
 
#endif  /* _winmain_ */ 
 
            /* 
             * note that if the exe is managed app, we don't really need to 
             * call exit or _c_exit. .cctor should be able to take care of 
             * this. 
             */ 
            if ( !managedapp ) 
                exit(mainret); 
 
            if (has_cctor == 0) 
                _cexit(); 
 
        } 
        __except ( _xcptfilter(getexceptioncode(), getexceptioninformation()) ) 
        { 
            /* 
             * should never reach here 
             */ 
 
            mainret = getexceptioncode(); 
 
            /* 
             * note that if the exe is managed app, we don't really need to 
             * call exit or _c_exit. .cctor should be able to take care of 
             * this. 
             */ 
            if ( !managedapp ) 
                _exit(mainret); 
 
            if (has_cctor == 0) 
                _cexit(); 
        } /* end of try - except */ 
 
        return mainret; 
}</span> 
我关心的是对于如下程序,类的构造和析构程序执行的时机:
[html]
<span style="font-size:18px;">class csayhello 

public: 
    csayhello() 
    { 
        cout<<"constructor csayhello"<<endl; 
    } 
 
    ~csayhello() 
    { 
        cout<<"deconstructor csayhello"<<endl; 
    } 
}; 
 
csayhello sayhello; 
 
int main() 

    csayhello sayhello1; 
    return 0; 

</span> 
很显然输出结果为:
[html]
<span style="font-size:18px;">constructor csayhello // 1</span> 
[html]
<span style="font-size:18px;">constructor csayhello // 2</span> 
[html]
<span style="font-size:18px;">deconstructor csayhello // 3</span> 
[html]
<span style="font-size:18px;">deconstructor csayhello // 4</span> 
第1句在__tmaincrtstartup中的_initterm( __xc_a, __xc_z )函数中输出
第2句进入main主函数后输出
第3句在执行到return 0时输出
第4句在退出main函数时,进入tmaincrtstartup函数中的exit函数中执行。

摘自 xudacheng06的专栏