语言那点事,crt
C語言標準(不管是ANSI 還是ISO)包含2部分,一部分是語言本身的標準,另一部分是C標準函數庫。C標準函數庫規定了函數的原型和功能,但是并沒限定這些函數要怎么實現。所謂滿足標準C規定的C編譯器,不僅指這個編譯器滿足C語言本身的標準,還指這個編譯器提供了一組滿足C標準庫的庫函數。這組庫函數是由編譯器廠商實現,并且滿足標準C規定的功能和接口的。這些庫函數,廠商并不一定要提供給用戶源文件給用戶編譯用,可以是二進制目標文件給用戶鏈接用(我猜這就是叫著運行庫的原因之一,你看不到源碼,能看到運行是的匯編碼)。
所以說,不管是哪個廠商的CRT,只要他宣稱他是標準的C編譯器,那他的CRT就肯定是滿足C標準中關于C標準庫的規定。廠商除了還可以對自己的CRT進行擴展,因此,是CRT中包含了標準C庫,而不是C庫中包含了CRT。
同時還應該說明,C庫函數里的有些函數需要操作系統支持才能實現的,比如printf和scanf函數等,這些函數管理輸入和輸出,但實際函數的底層是調用了操作系統提供的接口函數(實際就是系統調用)和實際的輸入輸出設備打交道(我猜這是叫C運行庫的另外一個原因,它的某些功能要運行在操作系統的支持之上)。
大概你又要迷惑為什么又牽涉進來操作系統了。簡單的講,操作系統就是管理計算機軟硬件資源,并為上層應用提供統一系統調用接口的一組程序。操作系統為我們管理千差萬別的硬件,并為上層(這里是CRT)提供統一的系統調用接口。舉例來說:輸入設備千差萬別:有串口,鼠標,鍵盤,觸摸屏等等,由操作系統管理這些輸入設備的差別,然后提供給scanf提供一個系統調用來得容易還是由C標準自己規定遇到每種不同的輸入設備應該怎么動作來得容易?
1)運行時庫即便 C run-time library,是 C 而非 C++ 語言世界的觀念:取這個名字即便因為你的 C 過程運行時必需這些庫中的函數.
2)C 語言是所謂的“小內核”語言,就其語言本身來說很小(不多的關鍵字,過程流程扼制,數據種類等);因而,C語言內核開發出來爾后,Dennis Ritchie 和 Brian Kernighan 就用 C 本身重寫了 90% 以上的 UNIX系統函數,并且把其中最常用的局部自力更生出來,構成頭文件和對應的 LIBRARY,C run-time library 即便這么構成的。
3)隨后,隨著 C 語言的流行,各個 C 編譯器的出產商/個體/群體都順從老的傳統,在不同平臺上都有相對應的 StandardLibrary,但大局部告終都是與各個平臺有關的。由于各個 C 編譯器對 C 的扶持和會意有許多抵觸和精深的差異,因而就有了 ANSIC;ANSI C (主觀愿望上)翔實的法定了 C 語言各個要素的翔實含義和編譯器告終要求,引進了新的函數聲明措施,同時訂立了 StandardLibrary 的規范形式。因而C運行時庫由編譯器出產商供給。至于由其他廠商/個人/群體供給的頭文件和庫函數,該當稱為第三方 C運行庫(Third party C run-time libraries)。
4)C run-time library里面含有初始化代碼,還有訛謬處理代碼(例如divide byzero處理)。你寫的過程能夠未曾math庫,過程照樣運行,只是不能處理混雜的數學計算,不過萬一未曾了Crun-time庫,main()就不會被調用,exit()也不能被響應。因為C run-timelibrary包括了C過程運行的最大約和最常用的函數。
5)到了 C++ 世界里,有另外一個觀念:Standard C++ Library,貝爾萊德蒸汽掛燙機它包括了上面所說的 C run-timelibrary 和 STL。包括 C run-time library 的起因很顯明,C++ 是 C 的超集,沒合原因再重新來一個 C++run-time library. VC針對C++ 加入的Standard C++ Library重要包括ar.artboard.net.cn:LIBCP.LIB,LIBCPMT.LIB和 MSVCPRT.LIB
6)Windows環境下,VC供給的 C run-time library又分為動態運行時庫和靜態運行時庫。
動態運行時庫重要是DLL庫文件msvcrt.dll(or MSVCRTD.DLL for debug build),對應的Import library文件是MSVCRT.LIB(MSVCRTD.LIB for debug build)
靜態運行時庫(release版)對應的重要文件是:
LIBC.LIB (Single thread static library, retail version)
LIBCMT.LIB (Multithread static library, retail version)
msvcrt.dll供給幾千個C函數,即便是像printf這么低級的函數都在msvcrt.dll里。其實你的過程運行時,很大一局部工夫時在這些運行庫里運行。在你的過程(release版)被編譯時,VC會依據你的編譯選項(單線程、多線程或DLL)積極將相應的運行時庫文件(libc.lib,libcmt.lib或Importlibrary msvcrt.lib)鏈接進來。
編譯時究竟哪個C run-time library聯入你的過程取決于編譯選項:
/MD, /ML, /MT, /LD (Use Run-Time Library)
你能夠VC中穿越以下措施設置抉擇哪個C run-time library聯入你的過程:
To find these options in the development environment, clickSettings on the Project menu. Then click the C/C++ tab, and clickCode Generation in the Category box. See the Use Run-Time Librarydrop-down box.
從過程可移植性琢磨,萬一兩函數都可告終一種功能,選運行時庫函數好,因為各個 C 編譯器的出產商對規范C Run-timelibrary供給了統一的扶持.他倒感受像C++這么的語言的OO,純是添亂。
一 C Run-TimeLibraries的三種可用形式 Win32 SDK提供了三種C Run-time library的可用形式 LIBC.LIB:單線程程序靜態鏈接到運行時庫 LIBCMT.LIB:多線程程序靜態鏈接到運行時庫 CRTDLL.LIB:CRTDLL.DLL的導入庫,支持多線程程序的鏈接。CTRDLL.DLL 本身是Windows NT的一部分。 ms vc++32位 版本同時包含了這三種運行時庫,不過CRT 動態庫被命名為MSVCRT.LIB。 這個動態鏈接庫是可重新發布的。它的名字取決于vc++的版本(MSVCRT10.DLL 或者MSVCRT20.DLL)。注意,win32不載支持MSVCRT10.DLL,但是支持CRTDLL.LIB;MSVCRT20.DLL有兩個版本,一個是windowsnt版,另一個是win32版。 二 當生成一個DLL時使用CRTLibraries 在生成一個DLL時,無論使用了哪個C Run-timelibraries庫,都要保證所使用的CRT被正確的初始化。可以使用下面任何一種方法: 1 初始化函數必須被命名為:DllMain() 并且入庫點必須在連接器選項中必須指定入口點位:_DllMainCrtStartup@12-或者-。 2在附加進程和分離進程的過程中,這個DLL的入庫點必須顯式調用CRT_INIT()。 這樣當一個進程或者線程連接到這個DLL時,C運行時庫可以正確的分配和初始化數據,并且當進程或者線程離開DLl時候可以正確的清理掉運行時庫, DLL中的全局C++對象(globalC++ objects)也可以正確的構造和解構。 下面的Win32 SDK例子程序都使用了第一種方法。請參考 win32programmer's reference for DllentryPoint() and the Vc++documentation for DllMain(). 注意函數DllMainCRTStartup()調用了 CRT_INIT(), 而CRT_INIT()在退出前將調用你的程序的DllMain()。如果你希望使用第二種方法來在自己調用CRT初始化代碼,而不使用DllMainCRTStartup()和 DllMain()函數,你可以使用兩種技術: 1 如果沒有入口函數來執行初始化代碼,只需要指定CRT_INIT()作為該DLL的入口點。假設你已經包含了文件NTWIN#@.MAK,?這個文件定義DLLENTRY 為"@12",?加入以下選項到DLL的鏈接選項命令行: -entry:_CRT_INIT$(DLLENTRY) - or - 2 如果你確實想擁有自己的DLL入口點,在入口點做如下的事情: a使用CRT_INIT()的原形: BOOLWINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOIDlpReserved) ; 關于CRT_INIT()的返回值,可以看 documentation DllEntryPoint,它返回了相同的返回值。 b 在DLL_PROCESS_ATTACH 和DLL_THREAD_ATTACH塊中, 在調用任何C 運行時庫函數和對任何浮點指針操作前首先調用CRT_INIT()。 c 調用自己的進程/線程 初始/結束代碼。 d 在DLL_PROCESS_DETACH和DLL_THREAD_DETACH中,在所有的C運行時庫函數被調用,并且所有浮點指針操作完成以后,最后一次調用CRT_INIT()。 要確保向CRT_INIT()傳遞了入口點的所有參數。CRT_INIT()需要這些這些參數。如果參數沒有全部傳遞過去,可能不能穩定運行(尤其需要fdwReason參數來確定進程的初始化或者結束)。下邊實例關于如何在入口點調用CRT_INIT()。 BOOL WINAPIDllEntryPoint(HINSTANCE hinstDll, DWORD fdwReason, LPVOIDlpReserved) { if (fdwReason ==DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH) if(!_CRT_INIT(hinstDll, fdwReason, lpReserved)) return (FALSE) ; if(fdwReason==DLL_PROCESS_DETACH || fdwReason==DLL_THREAD_DETACH) if(!_CRT_INIT(hinstDLL, fdwReason, lpReserved)) return (FALSE) ; return (TRUE) ; } 當然,如果使用DLLMain()并且設置了鏈接選項:-entry:_DllMainCRTStartup@12,則上述代碼就不需要了。 三使用NTWIN32.MAK來簡化生成過程 在NTWIN32.MAK中的宏定義可以幫助你簡化makefiles,并且可以確保正確的生成而避免沖突產生。因此,ms強烈推薦使用NTWIN32.MAK以及它所包含的宏。 編譯使用: $(cvarsdll)??for apps/DLLs using CRT in a DLL 鏈接使用下列行中的一個: $(conlibstdll)???forconsole apps/DLLs using CRT in a DLL $(guilibsdll)????for GUI apps using CRT in a DLL 四 當使用Multiple CRT庫是可能遇到的問題 如果一個使用了C運行時調用的應用程序,鏈接到另一個也使用了了C運行時調用的DLL,注意如果他們都連接到了一個C運行時的靜態庫(LIBC.LIB 或者 LIBCMT.LIB), 這個EXE和DLL將各自擁有C運行時的單獨的拷貝和全局變量。這意味著C運行時數據不能被這個.EXE和.DLL所共享。當進行以下操作時會產生問題: 1 從.EXE 或者.DLL傳遞緩沖流句柄(bufferd streamhandles)到另一個模塊 2 使用C運行時庫在一個模塊中分配一塊內存,而在另外一個模塊中對這個內存進行重分配操作或者是房內存操作(allocrealloc)。 3 在.EXE或者.DLL模塊中檢查或者設置一個全局錯誤號變量(globalerrnovariable)的值,而期望在另外的模塊中會獲得同樣的值。另外一個相關的錯誤操作是:在未產生錯誤的模塊中調用perror()函數。(perror()會使用錯誤號) 為了避免這些問題,應該把.EXE和.DLL都連接上 CRTDLL.LIB 或者 MSVCRT.LIB。這樣允許.EXE和.DLL都是使用在 動態CRT中包含的公共函數集和數據, 并且C運行時數據,例如流句柄,可以被.EXE和.DLL所共享。 五混合庫類型的裝入問題(不懂,待譯。有懂得人請指教) You can link your DLL with CRTDLL.LIB/MSVCRT.LIB regardless ofwhat your .EXE is linked with if you avoid mixing CRT datastructures and passing CRT file handles or CRT FILE* pointers toother modules.When mixing library types adhere to the following:
| ? | CRT file handles may only be operated on by the CRT module thatcreated them. |
| ? | CRT FILE* pointers may only be operated on by the CRT modulethat created them. |
| ? | Memory allocated with the CRT function malloc() may only befreed or reallocated by the CRT module that allocated it. |
If DLL A allocates a block of memory with malloc(), only DLL A maycall free(), _expand(), or realloc() to operate on that block. Youcannot call malloc() from DLL A and try to free that block from the.EXE or from DLL B.
NOTE: If all three modules were linked withCRTDLL.LIB or all three were linked with MSVCRT.LIb, theserestrictions would not apply. When linking DLLs with LIBC.LIB, be aware that if there is apossibility that such a DLL will be called by a multithreadedprogram, the DLL will not support multiple threads running in theDLL at the same time, which can cause major problems. If there is apossibility that the DLL will be called by multithreaded programs,be sure to link it with one of the libraries that supportmultithreaded programs (LIBCMT.LIB, CRTDLL.LIB orMSVCRT.LIB). ?五附加英文原文
Section 1: Three Forms of C Run-Time (CRT)Libraries Are Available
There are three forms of the C Run-time library provided with theWin32 SDK:| ? | LIBC.LIB is a statically linked library for single-threadedprograms. |
| ? | LIBCMT.LIB is a statically linked library that supportsmultithreaded programs. |
| ? | CRTDLL.LIB is an import library for CRTDLL.DLL that alsosupports multithreaded programs. CRTDLL.DLL itself is part ofWindows NT. |
Section 2: Using the CRT Libraries WhenBuilding a DLL
When building a DLL which uses any of the C Run-time libraries, inorder to ensure that the CRT is properly initialized, either
| 1. | the initialization function must be named DllMain() and theentry point must be specified with the linker option-entry:_DllMainCRTStartup@12 - or - |
| 2. | the DLL's entry point must explicitly call CRT_INIT() onprocess attach and process detach |
The Win32 SDK samples all use the first method. Use them as anexample. Also refer to the Win32 Programmer's Reference forDllEntryPoint() and the Visual C++ documentation for DllMain().Note that DllMainCRTStartup() calls CRT_INIT() and CRT_INIT() willcall your application's DllMain(), if it exists.
If you wish to use the second method and call the CRTinitialization code yourself, instead of using DllMainCRTStartup()and DllMain(), there are two techniques:
| 1. | if there is no entry function which performs initializationcode, simply specify CRT_INIT() as the entry point of the DLL.Assuming that you've included NTWIN32.MAK, which defines DLLENTRYas "@12", add the following option to the DLL's linkline: -entry:_CRT_INIT$(DLLENTRY) - or - | ||||||||
| 2. | if you *do* have your own DLL entry point, do the following inthe entry point:
Below is a skeleton sample entry point function that shows when andhow to make these calls to CRT_INIT() in the DLL entrypoint: BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpReserved){if (fdwReason == DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH)if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))return(FALSE);if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH)if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))return(FALSE);return(TRUE);} NOTE that this is *not* necessary ifyou are using DllMain() and-entry:_DllMainCRTStartup@12. |
Section 3: Using NTWIN32.MAK to Simplify theBuild Process
There are macros defined in NTWIN32.MAK that can be used tosimplify your makefiles and to ensure that they are properly builtto avoid conflicts. For this reason, Microsoft highly recommendsusing NTWIN32.MAK and the macros therein.For compilation, use: $(cvarsdll) for apps/DLLs using CRT in a DLL For linking, use one of the following: $(conlibsdll) for console apps/DLLs using CRT in a DLL$(guilibsdll) for GUI apps using CRT in a DLL
Section 4: Problems Encountered When UsingMultiple CRT Libraries
If an application that makes C Run-time calls links to a DLL thatalso makes C Run-time calls, be aware that if they are both linkedwith one of the statically-linked C Run-time libraries (LIBC.LIB orLIBCMT.LIB), the .EXE and DLL will have separate copies of all CRun-time functions and global variables. This means that C Run-timedata cannot be shared between the .EXE and the DLL. Some of theproblems that can occur as a result are:| ? | Passing buffered stream handles from the .EXE/DLL to the othermodule |
| ? | Allocating memory with a C Run-time call in the .EXE/DLL andreallocating or freeing it in the other module |
| ? | Checking or setting the value of the global errno variable inthe .EXE/DLL and expecting it to be the same in the other module. Arelated problem is calling perror() in the opposite module fromwhere the C Run- time error occurred, since perror() useserrno. |
Section 5: Mixing Library Types
You can link your DLL with CRTDLL.LIB/MSVCRT.LIB regardless of whatyour .EXE is linked with if you avoid mixing CRT data structuresand passing CRT file handles or CRT FILE* pointers to othermodules.When mixing library types adhere to the following:
| ? | CRT file handles may only be operated on by the CRT module thatcreated them. |
| ? | CRT FILE* pointers may only be operated on by the CRT modulethat created them. |
| ? | Memory allocated with the CRT function malloc() may only befreed or reallocated by the CRT module that allocated it. |
If DLL A allocates a block of memory with malloc(), only DLL A maycall free(), _expand(), or realloc() to operate on that block. Youcannot call malloc() from DLL A and try to free that block from the.EXE or from DLL B.
NOTE: If all three modules were linked withCRTDLL.LIB or all three were linked with MSVCRT.LIb, theserestrictions would not apply. When linking DLLs with LIBC.LIB, be aware that if there is apossibility that such a DLL will be called by a multithreadedprogram, the DLL will not support multiple threads running in theDLL at the same time, which can cause major problems. If there is apossibility that the DLL will be called by multithreaded programs,be sure to link it with one of the libraries that supportmultithreaded programs (LIBCMT.LIB, CRTDLL.LIB orMSVCRT.LIB).
轉載于:https://www.cnblogs.com/ShaneZhang/p/3480934.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
- 上一篇: (转)OpenSSL命令---pkcs1
- 下一篇: Qt字符串与整形转换