• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 319, comments - 22, trackbacks - 0, articles - 11
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            在VC中編譯、運行程序的小知識點

            Posted on 2011-05-12 22:06 RTY 閱讀(531) 評論(0)  編輯 收藏 引用 所屬分類: 編程常識C/C++轉載隨筆

            1、Run-Time Library

            Run-Time Library是編譯器提供的標準庫,提供一些基本的庫函數和系統調用。
            我們一般使用的Run-Time Library是C Run-Time Libraries。當然也有Standard C++ libraries。 
            C Run-Time Libraries實現ANSI C的標準庫。VC安裝目錄的CRT目錄有C Run-Time庫的大部分源代碼。

            C Run-Time Libraries有靜態庫版本,也有動態鏈接庫版本;有單線程版本,也有多線程版本;還有調試和非調試版本。
            可以在"project"-"settings"-"C/C++"-"Code Generation"中選擇Run-Time Library的版本。

            動態鏈接庫版本:
            /MD Multithreaded DLL 使用導入庫MSVCRT.LIB
            /MDd Debug Multithreaded DLL 使用導入庫MSVCRTD.LIB

            靜態庫版本:
            /ML Single-Threaded 使用靜態庫LIBC.LIB 
            /MLd Debug Single-Threaded 使用靜態庫LIBCD.LIB
            /MT Multithreaded 使用靜態庫LIBCMT.LIB
            /MTd Debug Multithreaded 使用靜態庫LIBCMTD.LIB

            C Run-Time Library的標準io部分與操作系統的關系很密切,在Windows上,CRT的io部分代碼只是一個包裝,底層要用到操作系統內核kernel32.dll中的函數,在編譯時使用導入庫kernel32.lib。這也就是為什么在嵌入式環境中,我們一般不能直接使用C標準庫。
            在Linux環境當然也有C標準庫,例如:
            ld -o output /lib/crt0.o hello.o -lc
            參數"-lc"就是在引用C標準庫libc.a。猜一猜"-lm"引用哪個庫文件?

            2、常見的編譯參數

            VC建立項目時總會定義"Win32"。控制臺程序會定義"_CONSOLE",否則會定義"_WINDOWS"。Debug版定義"_DEBUG",Release版定義"NDEBUG"

             

            與MFC DLL有關的編譯常數包括:
            _WINDLL 表示要做一個用到MFC的DLL
            _USRDLL 表示做一個用戶DLL(相對MFC擴展DLL而言) 
            _AFXDLL 表示使用MFC動態鏈接庫
            _AFXEXT 表示要做一個MFC擴展DLL
            所以:
            Regular, statically linked to MFC _WINDLL,_USRDLL 
            Regular, using the shared MFC DLL _WINDLL,_USRDLL,_AFXDLL
            Extension DLL _WINDLL,_AFXDLL,_AFXEXT

            CL.EXE編譯所有源文件,LINK.EXE鏈接EXE和DLL,LIB.EXE產生靜態庫。

            3、subsystem和可執行文件的啟動

            LINK的時候需要指定/subsystem,這個鏈接選項告訴Windows如何運行可執行文件。
            控制臺程序是/subsystem:"console"
            其它程序一般都是/subsystem:"windows "

             

            將 subsystem 選成"console"后,Windows在進入可執行文件的代碼前(如mainCRTStartup),就會產生一個控制臺窗口。
            如果選擇"windows",操作系統就不產生console窗口,該類型應用程序的窗口由用戶自己創建。

            可執行文件都有一個Entry Point,LINK時可以用/entry指定。缺省情況下,如果subsystem是“console”,Entry Point是 mainCRTStartup(ANSI)或wmainCRTStartuup(UNICODE),即:
            /subsystem:"console" /entry:"mainCRTStartup" (ANSI)
            /subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)
            mainCRTStartup 或 wmainCRTStartuup 會調用main或wmain。
            值得一提的是,在進入應用程序的Entry Point前,Windows的裝載器已經做過C變量的初始化,有初值的全局變量擁有了它們的初值,沒有初值的變量被設為0。

            如果subsystem是“windows”,Entry Point是WinMain(ANSI)或wWinMain(UINCODE),即:
            /subsystem:"windows" /entry:"WinMainCRTStartup" (ANSI)
            /sbusystem:"windows" /entry:"wWinMainCRTStartup" (UINCODE)
            WinMainCRTStartup 或 wWinMainCRTStartup 會調用 WinMain 或 wWinMain。

            這些入口點函數,在CRT目錄都可以看到源代碼,例如(為了簡潔,我刪除了原代碼的一些條件編譯):

            void mainCRTStartup(void)
            {
                    int mainret;
            
                    /* Get the full Win32 version */
                    _osver = GetVersion();
                    _winminor = (_osver >> 8) & 0x00FF ;
                    _winmajor = _osver & 0x00FF ;
                    _winver = (_winmajor << 8) + _winminor;
                    _osver = (_osver >> 16) & 0x00FFFF ;
            
            #ifdef _MT
                    if ( !_heap_init(1) )               /* initialize heap */
            #else  /* _MT */
                    if ( !_heap_init(0) )               /* initialize heap */
            #endif  /* _MT */
                        fast_error_exit(_RT_HEAPINIT);  /* write message and die */
            
            #ifdef _MT
                    if( !_mtinit() )                    /* initialize multi-thread */
                        fast_error_exit(_RT_THREAD);    /* write message and die */
            #endif  /* _MT */
            
                    __try {
                        _ioinit();                      /* initialize lowio */
                        _acmdln = (char *)GetCommandLineA();        /* get cmd line info */
                        _aenvptr = (char *)__crtGetEnvironmentStringsA();        /* get environ info */
                        _setargv();
                        _setenvp();
                        __initenv = _environ;
                        mainret = main(__argc, __argv, _environ);
                        exit(mainret);
                    }
                    __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
                    {
                        _exit( GetExceptionCode() );        /* Should never reach here */
                    } /* end of try - except */
            }  

            如果使用MFC框架,WinMain也會被埋藏在MFC庫中(APPMODUL.CPP):
            extern "C" int WINAPI
            _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPTSTR lpCmdLine, int nCmdShow)
            {
            // call shared/exported WinMain
            return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
            }
            對于ANSI版本,"_tWinMain"就是"WinMain";對于UINCODE版本,"_tWinMain"就是"wWinMain"。可參見afx.h:

            #ifdef _UNICODE
            #define _tmain wmain
            #define _tWinMain wWinMain
            #else
            #define _tmain main
            #define _tWinMain WinMain
            #endif

            全局C++對象的構造函數是在什么地方調用的?答案是在進入應用程序的Entry Point后,在調用main函數前的初始化操作中。所以MFC的theApp的構造函數是在_tWinMain之前調用的。

            4、不顯示Console窗口的Console程序

            在默認情況下/subsystem 和/entry開關是匹配的,也就是:
            "console"對應"mainCRTStartup"或者"wmainCRTStartup"
            "windows"對應"WinMain"或者"wWinMain"
            我們可以通過手動修改的方法使他們不匹配。例如:

             

            #include "windows.h"
            #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 設置入口地址 
            void main(void)
            {
            MessageBox(NULL, "hello", "Notice", MB_OK);
            }

            這個Console程序就不會顯示Console窗口。如果選/MLd的話,這個程序只需要鏈接LIBCD.LIB user32.lib kernel32.lib。

            其實如果不想看到Console窗口,還有一個更直接的方法:那就是直接在EXE文件中將PE文件頭的Subsystem從3改成2。在EXE文件中,PE文件頭的偏移地址是0x3c,Subsystem是一個WORD,它在PE文件頭中的偏移是0x5c。

            5、MFC的庫文件

            MFC的庫可以靜態鏈接,也可以動態鏈接。靜態庫和動態庫又有Debug和Release,ANSI和Unicode版本之分。

             

            靜態MFC庫主要有:
            ANSI Debug NAFXCWD.LIB
            ANSI Release NAFXCW.LIB
            Unicode Debug UAFXCWD.LIB
            Unicode Release UAFXCW.LIB 

            動態鏈接庫主要有;
            ANSI Debug MFCxxD.LIB (core,MFCxxD.DLL), 
            MFCOxxD.LIB (OLE,MFCOxxD.DLL), 
            MFCDxxD.LIB (database,MFCDxxD.DLL), 
            MFCNxxD.LIB (network,MFCNxxD.DLL), 
            MFCSxxD.LIB (static)

            ANSI Release MFCxx.LIB (combined,MFCxx.DLL)
            MFCSxx.LIB (static)

            Unicode Debug MFCxxUD.LIB (core,MFCxxUD.DLL), 
            MFCOxxUD.LIB (OLE,MFCOxxUD.DLL), 
            MFCDxxUD.LIB (database,MFCDxxUD.DLL), 
            MFCNxxUD.LIB (network,MFCNxxUD.DLL), 
            MFCSxxUD.LIB (static)

            Unicode Release MFCxxU.DLL (combined,MFCxxU.DLL), 
            MFCSxxU.LIB (static)

            上面的LIB文件除了MFCSxx(D、U、UD).LIB以外都是導入庫。
            MFC動態鏈接庫版本也需要靜態鏈接一些文件,這些文件就放在MFCSxx(D、U、UD).LIB中。例如包含_tWinMain的appmodul.cpp。

            6、結束語

            研究這些問題的動機是想弄清楚我們的程序是如何裝載、運行的。但是,由于Windows不是開源平臺,我也只能研究到PE文件(Windows上可執行文件的格式)。entry point、subsystem都是PE文件頭的一部分。

            Windows在進入PE文件的entry point之前做了些什么,就看不到了,只能大概推測:應該是創建一個進程,裝載PE文件和所有需要的DLL,初始化C變量,然后從某個起點函數開始運行。不同的subsystem,應該有不同的起點。調用這個起點函數時應該傳入PE文件的entry point地址。

             

            久久久久国产精品人妻| 久久国产成人午夜aⅴ影院| 久久精品一区二区三区中文字幕 | 成人午夜精品无码区久久| 91精品观看91久久久久久| 国产成人精品久久亚洲高清不卡 | 亚洲狠狠久久综合一区77777| 精品久久久久久中文字幕| 精品午夜久久福利大片| 精品乱码久久久久久夜夜嗨| 久久综合久久鬼色| 伊人久久精品无码av一区| 国内精品久久久久久99蜜桃| 久久精品成人| 久久久久这里只有精品| 色妞色综合久久夜夜| 日韩精品久久久久久| 久久只有这里有精品4| 性做久久久久久久| 精品久久久久久无码人妻蜜桃| 久久国产精品波多野结衣AV| 亚洲AV无码久久精品蜜桃| 91精品国产高清久久久久久国产嫩草| 欧美激情精品久久久久久久九九九| 少妇人妻综合久久中文字幕| 久久国产高清字幕中文| 麻豆国内精品久久久久久| 精品国产一区二区三区久久| 一级a性色生活片久久无少妇一级婬片免费放| 久久久久久免费视频| 久久亚洲国产中v天仙www| 77777亚洲午夜久久多喷| 66精品综合久久久久久久| 亚洲av日韩精品久久久久久a| 国内精品欧美久久精品| 色综合久久综精品| 久久精品亚洲日本波多野结衣| 国产精品久久久久蜜芽| 久久免费大片| 91精品久久久久久无码| 久久婷婷激情综合色综合俺也去|