现在的位置: 首页 > 综合 > 正文

C/C++启动函数

2013年08月02日 ⁄ 综合 ⁄ 共 5586字 ⁄ 字号 评论关闭

今天在看《Windows核心编程》第四章,其中我感兴趣的是关于启动函数的描述。

启动函数的用途如下:

1,获取指向新进程的完整命令行的一个指针;

2,获取指向新进程的环境变量的一个指针;

3,初始化C/C++运行库的全局变量

4,初始化所有全局和静态C++类对象的构造函数。

对于一个程序而言,在执行main函数之前会执行crtexe.c文件中mainCRTStartup或wmainCRTStartup函数,如下所示:

#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();
}

__tmainCRTStartup函数如下所示:

__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 vcclrit.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;
            mainret = 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;
}

我关心的是对于如下程序,类的构造和析构程序执行的时机:

class CSayHello
{
public:
	CSayHello()
	{
		cout<<"Constructor CSayHello"<<endl;
	}

	~CSayHello()
	{
		cout<<"Deconstructor CSayHello"<<endl;
	}
};

CSayHello sayHello;

int main()
{
    CSayHello sayHello1;
    return 0;
}

很显然输出结果为:

Constructor CSayHello // 1
Constructor CSayHello // 2
Deconstructor CSayHello // 3
Deconstructor CSayHello // 4

第1句在__tmainCRTStartup中的_initterm(
__xc_a, __xc_z )函数中输出

第2句进入main主函数后输出

第3句在执行到return 0时输出

第4句在退出main函数时,进入tmainCRTStartup函数中的exit函数中执行。










【上篇】
【下篇】

抱歉!评论已关闭.