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 */