语言那点事,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.
To illustrate this, consider the following example:
   - .EXE is linked with MSVCRT.LIB
   - DLL A is linked with LIBCMT.LIB
   - DLL B is linked with CRTDLL.LIB
If the .EXE creates a CRT file handle using _create() or_open(), this file handle may only be passed to _lseek(), _read(),_write(), _close(), etc. in the .EXE file. Do not pass this CRTfile handle to either DLL. Do not pass a CRT file handle obtainedfrom either DLL to the other DLL or to the .EXE.

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.
Microsoft Visual C++ 32-bit edition contains these three forms aswell, however, the CRT in a DLL is named MSVCRT.LIB. The DLL isredistributable. Its name depends on the version of VC++ (ieMSVCRT10.DLL or MSVCRT20.DLL). Note however, that MSVCRT10.DLL isnot supported on Win32s, while CRTDLL.LIB is supported on Win32s.MSVCRT20.DLL comes in two versions: one for WindowsNT and the other for Win32s.

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
This permits the C Run-time libraries to properly allocate andinitialize C Run-time data when a process or thread is attaching tothe DLL, to properly clean up C Run-time data when a process isdetaching from the DLL, and for global C++ objects in the DLL to beproperly constructed and destructed.

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:

a. Use this prototype for CRT_INIT():
BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpReserved);
For information on CRT_INIT() return values, see the documentationDllEntryPoint; the same values are returned.
b. On DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH (see"DllEntryPoint" in the Win32 API reference for more information onthese flags), call CRT_INIT(), first, before any C Run-timefunctions are called or any floating-point operations areperformed.
c. Call your own process/thread initialization/terminationcode.
d. On DLL_PROCESS_DETACH and DLL_THREAD_DETACH, call CRT_INIT()last, after all C Run-time functions have been called and allfloating- point operations are completed.
Be sure to pass on to CRT_INIT() all of the parameters of the entrypoint; CRT_INIT() expects those parameters, so things may not workreliably if they are omitted (in particular, fdwReason is requiredto determine whether process initialization or termination isneeded).

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.
To avoid these problems, link both the .EXE and DLL with CRTDLL.LIBor MSVCRT.LIB, which allows both the .EXE and DLL to use the commonset of functions and data contained within CRT in a DLL, and CRun-time data such as stream handles can then be shared by both the.EXE and DLL.

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.
To illustrate this, consider the following example:
   - .EXE is linked with MSVCRT.LIB
   - DLL A is linked with LIBCMT.LIB
   - DLL B is linked with CRTDLL.LIB
If the .EXE creates a CRT file handle using _create() or_open(), this file handle may only be passed to _lseek(), _read(),_write(), _close(), etc. in the .EXE file. Do not pass this CRTfile handle to either DLL. Do not pass a CRT file handle obtainedfrom either DLL to the other DLL or to the .EXE.

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