C运行库是什么?

211
什么是C运行时库?它有什么用途?我进行了搜索和谷歌,但没有找到比微软的更好的解释:“Microsoft运行时库提供了编程Microsoft Windows操作系统所需的例程。这些程序自动化了许多常见的编程任务,这些任务不会被C和C++语言提供。”
嗯,我明白了,但是比如说,libcmt.lib中有什么?它是做什么的?我原本以为C标准库是C编译器的一部分。那么libcmt.lib是Windows下实现C标准库函数以在win32下工作的吗?

这份来自Microsoft的官方文档可能会很有用。 https://support.microsoft.com/en-in/help/94248/how-to-use-the-c-run-time - Manojkumar Khotele
8个回答

93

是的,libcmt是微软编译器提供的C标准库的(多个)实现之一。它们提供三种基本类型的库的“调试”和“发布”版本: 单线程(总是静态链接),多线程静态链接多线程动态链接(但是根据您使用的编译器版本,其中一些可能不存在)。

所以,在名称“libcmt”中,“libc”是 C 库的传统名称。 “mt”表示“多线程”。 “调试”版本会在结尾加上“d”,得到“libcmtd”。

至于它包含哪些函数,C 标准(第 7 部分,如果您恰好关心)定义了符合(托管)实现必须提供的函数集。大多数供应商(包括 Microsoft)自己添加各种其他功能(用于兼容性,提供标准函数未涉及的功能等)。在大多数情况下,它还包含许多“内部”函数,这些函数由编译器使用,但终端用户通常不使用。

运行时库基本上是一个将这些函数的实现收集到一个大文件中(或者几个大文件 - 例如,在 UNIX 上,浮点函数通常存储在与其余函数分开的地方)的集合。该大文件通常是与 zip 文件相同的量级,但没有任何压缩,因此它只是一些小文件集合,并存储在一个大文件中。档案通常至少包含一些索引,以使从内部文件中查找和提取数据相对快速/容易。至少在某些情况下,微软使用了具有“扩展”索引的库格式,链接器可以使用该索引找到哪些函数实现在子文件中,因此它可以更快地找到并链接其需要的部分(但这纯粹是一种优化,而不是要求)。

如果你想获取“libcmt”(以您的示例为例)中所有函数的完整列表,可以打开Visual Studio命令提示符之一(通常在“Visual Studio工具”下),切换到库安装目录并输入以下命令:lib -list libcmt.lib,它将生成一个(很长的)列表,其中列出了该库中所有对象文件的名称。它们不总是直接对应于函数的名称,但通常会给出一个大致的概念。如果您想查看特定对象文件,可以使用lib -extract提取其中一个对象文件,然后使用dumpbin /symbols <object file name>查找该特定对象文件中的哪个函数。


64
你还没有说明什么是"C运行时库"!! - onmyway133
6
@entropy:在我看来似乎是这样,但简短的回答是它是一组函数的集合,其中许多(但不一定全部)在C标准的第7部分中进行了说明。 - Jerry Coffin
6
这个答案暗示C库只是编译器工具链的一部分。这并不准确。 - jiggunjer
3
C运行时库基本上是微软用来指代标准C库的方式吗? - ZoomIn
3
@onmyway133,他确实回答了你的问题。你现在处于 XY 问题中。你认为你想找人告诉你什么是 C 运行时库,但是当有人(我必须说做得非常好和非常清楚)告诉你后,你仍然抱怨,因为你真正想问的是完全不同的问题,可能甚至不知道该如何表达,很可能是像“C 为什么需要运行时库?”这样的问题。 - Marcel Besixdouze
显示剩余6条评论

71
首先,我们应该了解什么是运行时库;并思考“Microsoft C Runtime Library”可能意味着什么。
参见:http://en.wikipedia.org/wiki/Runtime_library 当计算机程序的源代码通过编译器翻译成相应的目标语言时,如果每个命令和每个内置函数的每次调用都会导致在目标语言中生成完整的相应程序代码,则会导致程序代码极度膨胀。相反,编译器通常使用编译器特定的运行时库中的辅助函数,这些函数大部分不可由应用程序员访问。根据编译器制造商的不同,运行时库有时也包含相应编译器的标准库或被其包含。
此外,一些只能在运行时执行的函数(或更有效或准确的函数)被实现在运行时库中,例如一些逻辑错误、数组边界检查、动态类型检查、异常处理以及可能的调试功能。因此,一些编程错误可能不会在经过复杂的编译时检查和发布前测试后被发现,直到在真实数据的“实时”环境中测试程序时才会遇到运行时错误消息。
通常,运行时库通过访问操作系统来实现许多功能。许多编程语言具有内置函数,不一定必须在编译器中实现,但可以在运行时库中实现。因此,运行时库和标准库之间的边界取决于编译器制造商。因此,运行时库始终是特定于编译器和平台的。
运行时库的概念不应与应用程序员创建或由第三方提供的普通程序库混淆,也不应与动态库混淆,即在运行时链接的程序库。例如,编程语言C只需要一个最小的运行时库(通常称为crt0),但定义了一个大型的标准库(称为C标准库),每个实现都必须提供。

6
突出显示的这句话是一种与标准库区分的方式,这是我看到的第一个简洁准确的答案,而不带有“大多数”或“有时”的限定条件。 - nik.shornikov
@nik.shornikov:这是因为其他描述试图更准确。虽然标准库通常特定于编译器和平台,但并非总是如此。例如,至少某些版本的Mingw和Intel的Windows C++编译器使用了Microsoft的标准库而不是提供自己的标准库。同样,Linux上的Clang可以(并经常)安装以使用现有的gcc安装中的标准库,而不是为自己安装另一个标准库。 - Jerry Coffin
我相信可以编写C和C++标准库的实现,这些实现可在支持POSIX的任何平台上移植。 - Jerry Coffin

41
我刚刚思考了这个问题,已经费了几个小时但是仍然没有找到一个真正有意义的答案。每个写关于这个话题的人都无法真正“教”我们。如果你想要教某人,就使用一个最基础的语言,让那个人不需要担心其他关于这个话题的事情。所以我得出了自己的结论,似乎很适合在这种混乱中找到方向。

在编程语言C中,每个程序都从main()函数开始执行。其他语言可能会定义其他函数作为程序的起点。但处理器并不知道main()函数。处理器只知道预定义的命令,由01的组合表示。

在微处理器编程中,如果没有底层操作系统(如Microsoft Windows、Linux、MacOS等),您需要通过设置程序计数器(PC)来显式告诉处理器从哪里开始运行程序。PC会在处理器已知的命令之间进行迭代和跳转(循环、函数调用)。您需要知道RAM的大小,设置程序堆栈(本地变量)的位置,以及堆(动态变量)和全局变量(我猜它被称为SSA?)在RAM内的位置。单个处理器一次只能执行一个程序。

这就是操作系统发挥作用的地方。操作系统本身是在处理器上运行的程序,它允许执行自定义代码。通过在多个程序之间切换执行代码(这些代码加载到RAM中),同时运行多个程序。但是操作系统本身也是一个程序,每个程序都是以不同的方式编写的。仅将自定义程序代码放入RAM中并不能运行它,因为操作系统并不知道它。您需要调用操作系统的功能来注册您的程序,告诉操作系统程序需要多少内存,程序入口点位于何处(在C语言中为main()函数)。我猜这就是运行时库所在的位置,并解释了为什么每个操作系统都需要一个特殊的库,因为这些库本身也是程序,具有不同的功能来完成这些任务。

这也解释了为什么Runtime库不像.dll文件那样在运行时进行动态链接,即使它被称为运行时库。Runtime库需要静态链接,因为它在程序启动时需要。运行时库在运行时将您的自定义程序注入/连接到另一个程序(操作系统)中。这确实会引起一些困惑...结论: Runtime库的命名是失败的。早期可能没有.dll(在运行时链接)的概念,因此理解差异的问题并不存在。但即使如此,这个名称选择得很糟糕。更好的名称可以是:StartupLibrary/OSEntryLibrary/SystemConnectLibrary/OSConnectLibrary。希望我理解正确,有待修正/扩展。干杯。

4
我不太理解这个概念。为什么程序需要运行时的支持?为什么二进制代码不能完全独立地运行,而不需要在运行时得到任何支持?换句话说,是否有可能编写一个完全不需要任何支持(包括操作系统)就能100%运行的代码? - MarcioAB
10
理论上,一个程序并不_需要_实时语言库(RTL)。然而,如果没有操作系统的协助,你的程序如何显示其结果、获取任何输入或请求内存呢? - Motorhead
3
这是对这个问题最易懂的答案,感谢您。不过问题仍然是,“启动库”是否也实现了C标准库?就像C++那样,C标准是否也定义了一个库规范,并且该库是否也实现了相同的规范?请给我关于这个主题的启示。 - ZoomIn
7
你的结论是错误的,即启动程序需要提供main()函数的地址并且C运行时库没有动态链接。可执行文件(例如ELF可执行文件)包含入口点地址和其他运行程序所需的信息。此外,Microsoft C Runtime的名称应该能给你一个提示,它被称为"msvcrt.dll"。 - SeanRamey

20

C语言是一种语言,它的定义中并不需要为您提供任何函数。没有IO、没有数学例程等等。按照惯例,有一组可用于链接到您的可执行文件的例程,但您不必必须使用它们。然而,这是一个非常普遍的做法,以至于大多数链接器不再要求您链接到C运行时库。

有时候您可能不需要这些函数——例如,在嵌入式系统中工作时,可能无法使用malloc(动态内存分配)等函数。我曾经在打印机上嵌入PostScript,我们有自己的运行时库,适用于嵌入式系统,因此我们没有使用“标准”运行时库。


21
实际上,C标准描述了两种C环境——“自由环境”和“托管环境”——在托管环境中,标准描述的函数是可用的。在嵌入式系统中,C环境通常是自由环境,因此您可能没有库例程,或者可以避免使用某些库例程而使用自己的替代品。 - user862787

10

运行时库是自动编译进任何C程序中的库。所使用的库的版本取决于编译器、平台、调试选项和多线程选项。

关于不同运行时库选择的良好描述:http://www.davidlenihan.com/2008/01/choosing_the_correct_cc_runtim.html

它包括那些通常不需要调用库来调用的函数:

  • malloc
  • 枚举,结构体
  • abs,min
  • assert

Microsoft有一个他们的运行时库函数的很好的列表:

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/crt-alphabetical-function-reference?view=msvc-170

函数的确切列表会因编译器而异,因此对于iOS,您将获得其他函数,如dispatch_async()或NSLog()。


5
结构体和枚举类型真的是运行时库吗? - Dean P
1
@DeanP,不是的。structenum只是typedefs,基本上只是一种使用基本类型(如unsigned intlongsigned short)更加逻辑和结构化的语法糖。你根本不需要任何库代码或文本,因为它们在实际的二进制可执行文件中不存在!每个枚举值只是一个普通的数字,每个结构体字段只是用原始数据填充--结构体字段的“含义”是源代码概念,在二进制可执行文件或目标文件中根本不存在。 - Gregory Fenn
更新了“Microsoft有一个很好的运行时库函数列表”的链接(截至2022年):[链接]https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/crt-alphabetical-function-reference?view=msvc-170 和 [链接]https://learn.microsoft.com/en-us/cpp/c-runtime-library/c-run-time-library-reference?view=msvc-170#:~:text=Microsoft运行时库提供了许多常用例程,包括库中的大多数例程。 - andreyk2 Hohlov
@DeanP 不对!struct和enum是语言的一部分,而不是库。只需查看提供的URL以获取完整列表。 - S.M.Mousavi

6
如果您使用类似于Dependency Walker这样的工具来查看从C或C ++编译的可执行文件,您会发现它所依赖的DLL之一是MSVCRT.DLL。这是Microsoft C运行时库。如果您进一步使用DW检查MSVCRT.DLL,您会发现这里存放着所有函数,如printf(),puts(0, gets(),atoi()等。

6
只有在编译该可执行文件时动态链接了C运行时库,如果静态链接了,依赖项查看器将不会显示任何内容。 - Eli Bendersky

5
我认为微软的定义实际上是这样的:

标准C运行时库的微软实现提供了...


3

Win32 SDK提供了三种C运行时库:

* LIBC.LIB is a statically linked library for single-threaded programs.
* LIBCMT.LIB is a statically linked library that supports multithreaded programs.
* CRTDLL.LIB is an import library for CRTDLL.DLL that also supports multithreaded programs. CRTDLL.DLL itself is part of Windows NT. 

微软Visual C++ 32位版也包含这三种形式,但是在DLL中的CRT命名为MSVCRT.LIB。该DLL可重新分发。它的名称取决于VC++的版本(即MSVCRT10.DLL或MSVCRT20.DLL)。但请注意,MSVCRT10.DLL不支持Win32s,而CRTDLL.LIB支持Win32s。MSVCRT20.DLL有两个版本:一个用于Windows NT,另一个用于Win32s。

参见:http://support.microsoft.com/?scid=kb%3Ben-us%3B94248&x=12&y=9


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接