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

             

            欧美大香线蕉线伊人久久| 亚洲av成人无码久久精品| 99久久精品国内| 久久九九全国免费| 亚洲国产精品久久久久久| 国产精品美女久久久久AV福利| 国产99久久九九精品无码| 久久这里只精品99re66| 久久久久AV综合网成人| 久久精品三级视频| 亚洲精品无码成人片久久| 久久精品国产半推半就| 国产精品99久久久久久宅男小说| 欧美大香线蕉线伊人久久| 色偷偷88欧美精品久久久 | 国产美女久久精品香蕉69| 精品国产91久久久久久久a| 香蕉久久av一区二区三区| 国产精品成人精品久久久| 日韩人妻无码精品久久久不卡| 国产精品99久久不卡| 久久99国产综合精品| 国内精品久久久久影院老司| 免费观看久久精彩视频| 精品久久久久久无码中文字幕一区| 日本加勒比久久精品| 777久久精品一区二区三区无码| 久久亚洲精品成人AV| 国内精品人妻无码久久久影院导航| 亚洲国产精品久久久久婷婷软件| 久久久久久久久久久久中文字幕| 亚洲欧美成人综合久久久| 免费精品国产日韩热久久| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 国产精品久久网| 日本久久久久亚洲中字幕| 久久久久久精品免费免费自慰 | 亚洲人成无码网站久久99热国产| 国产日韩欧美久久| 激情综合色综合久久综合| 久久久久亚洲爆乳少妇无|