• <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 閱讀(526) 評論(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地址。

             

            久久久亚洲欧洲日产国码二区| 久久99热精品| 亚洲伊人久久成综合人影院 | 久久久久久精品久久久久| 久久人人爽人人爽人人片AV不| 伊人久久大香线蕉av一区| 精品久久一区二区三区| 热久久视久久精品18| 97r久久精品国产99国产精| 开心久久婷婷综合中文字幕| 国产亚洲综合久久系列| 四虎影视久久久免费观看| 99久久精品国产高清一区二区| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 99久久无色码中文字幕| 色婷婷噜噜久久国产精品12p| 久久精品中文闷骚内射| 亚洲国产小视频精品久久久三级| 精品一区二区久久久久久久网站| 四虎亚洲国产成人久久精品| 精品久久一区二区三区| 性欧美丰满熟妇XXXX性久久久| 久久精品无码一区二区三区日韩 | 久久无码AV一区二区三区| 国产精品热久久无码av| 国产Av激情久久无码天堂| 国产精品久久久久久五月尺| 久久久久国色AV免费观看| 99久久综合国产精品二区| 91超碰碰碰碰久久久久久综合| 少妇高潮惨叫久久久久久| 亚洲国产精品无码久久久秋霞2 | 99久久亚洲综合精品网站| 99精品国产在热久久| 精品精品国产自在久久高清| 久久久久久久亚洲Av无码| 久久精品一本到99热免费| 国产精品久久毛片完整版| 狠狠色噜噜狠狠狠狠狠色综合久久| 久久超乳爆乳中文字幕| 欧美精品一区二区精品久久 |