#5
樓主自己矛盾了,一會兒問為什么是零,一會兒又問怎么實現。
至於實現定義變量要看編譯原理了。
下面文章說明了誰在負責初始化。
下面文章的來源:
http://hi.baidu.com/b5000/blog/item/b4f9138291e123a10df4d243.html
C運行時庫詳解2007-12-14 21:15
運行時庫是程序在運行時所需要的庫文件,通常運行時庫是以LIB或DLL形式提供的。C運行時庫誕生於20世紀70年代,當時的程序世界還很單純,應用程序都是單線程的,多任務或多線程機制在此時還屬於新觀念。所以這個時期的C運行時庫都是單線程的。
隨着操作系統多線程技術的發展,最初的C運行時庫無法滿足程序的需求,出現了嚴重的問題。C運行時庫使用了多個全局變量(例如errno)和靜態變量,這可能在多線程程序中引起沖突。假設兩個線程都同時設置errno,其結果是后設置的errno會將先前的覆蓋,用戶得不到正確的錯誤信息。
因此,Visual C++提供了兩種版本的C運行時庫。一個版本供單線程應用程序調用,另一個版本供多線程應用程序調用。多線程運行時庫與單線程運行時庫有兩個重大差別:
(1)類似errno的全局變量,每個線程單獨設置一個;
這樣從每個線程中可以獲取正確的錯誤信息。
(2)多線程庫中的數據結構以同步機制加以保護。
這樣可以避免訪問時候的沖突。
Visual C++提供的多線程運行時庫又分為靜態鏈接庫和動態鏈接庫兩類,而每一類運行時庫又可再分為debug版和release版,因此Visual C++共提供了6個運行時庫。如下表:
C運行時庫 庫文件
Single thread(static link) libc.lib
Debug single thread(static link) libcd.lib
MultiThread(static link) libcmt.lib
Debug multiThread(static link) libcmtd.lib
MultiThread(dynamic link) msvert.lib
Debug multiThread(dynamic link) msvertd.lib
2.C運行時庫的作用
C運行時庫除了給我們提供必要的庫函數調用(如memcpy、printf、malloc等)之外,它提供的另一個最重要的功能是為應用程序添加啟動函數。
C運行時庫啟動函數的主要功能為進行程序的初始化,對全局變量進行賦初值,加載用戶程序的入口函數。
不采用寬字符集的控制台程序的入口點為mainCRTStartup(void)。下面我們以該函數為例來分析運行時庫究竟為我們添加了怎樣的入口程序。這個函數在crt0.c中被定義,下列的代碼經過了筆者的整理和簡化:
void mainCRTStartup(void)
{
int mainret;
/*獲得WIN32完整的版本信息*/
_osver = GetVersion();
_winminor = (_osver >> 8) & 0x00FF ;
_winmajor = _osver & 0x00FF ;
_winver = (_winmajor <
_osver = (_osver >> 16) & 0x00FFFF ;
_ioinit(); /* initialize lowio */
/* 獲得命令行信息 */
_acmdln = (char *) GetCommandLineA();
/* 獲得環境信息 */
_aenvptr = (char *) __crtGetEnvironmentStringsA();
_setargv(); /* 設置命令行參數 */
_setenvp(); /* 設置環境參數 */
_cinit(); /* C數據初始化:全局變量初始化,就在這里!*/
__initenv = _environ;
mainret = main( __argc, __argv, _environ ); /*調用main函數*/
exit( mainret );
}
從以上代碼可知,運行庫在調用用戶程序的main或WinMain函數之前,進行了一些初始化工作。初始化完成后,接着才調用了我們編寫的main或WinMain函數。只有這樣,我們的C語言運行時庫和應用程序才能正常地工作起來。
除了crt0.c外,C運行時庫中還包含wcrt0.c、 wincrt0.c、wwincrt0.c三個文件用來提供初始化函數。wcrt0.c是crt0.c的寬字符集版,wincrt0.c中包含windows應用程序的入口函數,而wwincrt0.c則是wincrt0.c的寬字符集版。
Visual C++的運行時庫源代碼缺省情況下不被安裝。如果您想查看其源代碼,則需要重裝Visual C++,並在重裝在時選中安裝運行庫源代碼選項。
3.各種C運行時庫的區別
(1)靜態鏈接的單線程庫
靜態鏈接的單線程庫只能用於單線程的應用程序,C運行時庫的目標代碼最終被編譯在應用程序的二進制文件中。通過/ML編譯選項可以設置Visual C++使用靜態鏈接的單線程庫。
(2)靜態鏈接的多線程庫
靜態鏈接的多線程庫的目標代碼也最終被編譯在應用程序的二進制文件中,但是它可以在多線程程序中使用。通過/MD編譯選項可以設置Visual C++使用靜態鏈接的單線程庫。
(3)動態鏈接的運行時庫
動態鏈接的運行時庫將所有的C庫函數保存在一個單獨的動態鏈接庫MSVCRTxx.DLL中,MSVCRTxx.DLL處理了多線程問題。使用/ML編譯選項可以設置Visual C++使用動態鏈接的運行時庫。
/MDd、 /MLd 或 /MTd 選項使用 Debug runtime library(調試版本的運行時刻函數庫),與/MD、 /ML 或 /MT分別對應。Debug版本的 Runtime Library 包含了調試信息,並采用了一些保護機制以幫助發現錯誤,加強了對錯誤的檢測,因此在運行性能方面比不上Release版本。
下面看一個未正確使用C運行時庫的控制台程序:
#include
#include
int main()
{
CFile file;
CString str("I love you");
TRY
{
file.Open("file.dat",CFile::modeWrite | CFile::modeCreate);
}
CATCH( CFileException, e )
{
#ifdef _DEBUG
afxDump <m_cause <
#endif
}
END_CATCH
file.Write(str,str.GetLength());
file.Close();
}
我們在"rebuild all"的時候發生了link錯誤:
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
main.exe : fatal error LNK1120: 2 unresolved externals
Error executing cl.exe.
發生錯誤的原因在於Visual C++對控制台程序默認使用單線程的靜態鏈接庫,而MFC中的CFile類已暗藏了多線程。我們只需要在Visual C++6.0中依次點選Project->Settings->C/C++菜單和選項,在Project Options里修改編譯選項即可。