C运行时库第2部分

时间:2010-05-10 23:09:28

标签: c runtime

当我对我的旧问题有一些进一步的问题时,我被建议创建更新的问题并参考旧的问题。所以,这是原始问题:What is the C runtime library?

好的,从您的回答中,我现在得到的静态链接库是Microsoft实现的C标准函数。现在:

如果我做对了,方案如下:我想使用printf(),所以我必须包含<stdio.h>,它只告诉编译器有一个带有这些参数的函数printf()。现在,当我编译代码时,因为printf()是在C标准库中定义的,并且因为Microsoft决定将其命名为C Run Time库,所以它会自动从libcmt.lib(如果libcmt.lib在编译器中设置)静态链接到编译时间。我问,因为在维基百科上,关于运行时库的文章中有运行时库在运行时链接,但.lib文件在编译时链接,我是对的吗?

现在,让我困惑的是什么。有.dll版本的C标准库。但我认为要链接.dll文件,你必须实际调用winapi程序来加载该库。那么,如果没有静态库提供代码告诉Windows从dll加载所需的函数,那么如何动态链接这些函数呢?

关于这个问题的最后一个问题 - C标准库函数是否也调用了winapi,即使它们不是像更高级的WinAPI函数那样的.dll文件?我的意思是,最后访问framebuffer并打印一些东西你必须告诉Windows这样做,因为OS不能让你直接操作HW。我认为它必须编写操作系统以支持所有C标准库函数在相似版本中的相同方式,因为它们是静态链接的,并且可以不同地支持更复杂的WinAPI调用,因为新版本的操作系统可以在.dll文件中进行调整

3 个答案:

答案 0 :(得分:3)

按顺序解决您的问题:

维基百科误导你。运行时库并不总是在运行时链接 ,而在您选择静态链接的运行时(libcmt.lib)的情况下则不会。

运行时库有一个.dll版本( 在运行时链接),编译器知道如何在.exe文件中生成相应的指令来告诉加载程序在运行时加载运行时库.dll

这里有两个API。一个是Win32 API,它是Windows操作系统本身支持的功能列表。另一个API是C运行时API,它由C编程语言标准定义。某些C运行时库函数(如打开和读取文件)最终将使Win32 API调用执行实际的文件I / O.其他C库函数(例如strlen())不与OS交互,而是使用完全在运行时库本身内部的代码实现。

答案 1 :(得分:2)

C Run Time中链接的是“main”函数的包装器;它可以在运行C代码之前初始化所需的所有内容。它不包含(m)任何“函数”,它们都在C标准库中(动态链接)。

我认为你误解了动态链接:它是由操作系统完成的。因此,您告诉操作系统您的可执行文件需要DLL abcd。执行可执行文件的时间,操作系统会将可执行文件加载到内存位置,并读取可执行文件运行它所需的内容。然后它会抓取这些DLL并将它们粘贴到可执行文件的内存区域,然后它会告诉您的代码a加载了xb加载到y等等,所以你的代码可以调用它的函数。

有时,编译器在编译时包含(称为静态链接)库:他们这样做,这样OS就不必在运行时加载它,因此加载速度更快。

.lib文件是没有“D”的DLL文件,因为它们可以静态链接。也可以动态链接库文件;这会使您的可执行文件变小,但会使您的可执行文件的加载时间变慢。

关于WinAPI:对C库的大多数调用都转换为(某些)调用到WinAPI中;但只有当他们必须与操作系统(I / O等)交互时。区别在于C库在大多数平台上是相同的,因此如果您直接使用C库而不是Windows API,它会增加可移植性。

更新

如果您完全动态链接可执行文件,您问如何加载DLL?嗯:你不必! “load dll”和“call to load dll”之间的区别是;启动应用程序时,“load dll”由操作系统完成。操作系统将在您的可执行文件中搜索特定的“导入表”。它是一个表格,说明它真正需要哪些DLL,然后才能执行(即Windows上的kernel32.dlluser32.dll)。即使在代码运行之前,操作系统也会进行“调用加载dll”。

“{1}}中还存在”调用加载dll“,以便调用您的代码:在您的代码运行时,可以加载/卸载DLL。如果您拥有庞大的代码库并且希望通过在整个应用程序生命周期内卸载该一次性使用库(例如,在启动期间)来释放内存,则可能出现这种情况。如果您不再使用该功能,则可以卸载DLL。但是你也可能需要一些尚未加载的功能来加速加载。如果您自己需要该功能,则可以加载DLL。这是非常先进的东西,大多数时候,操作系统将交换掉未使用的DLL(“删除”内存,字面意思是:它将未使用太多的内存(如未使用的DLL)移动到质量的地方存储,就像硬盘一样。如果你需要它,它会自动“交换”它!)。

所以:你不必担心在Windows上加载/卸载DLL。如果你有一个好的链接器,并告诉它动态链接库,那么一切都会正常。

答案 2 :(得分:1)

在Visual C ++和其他一些编译器中,CRT是为您链接的,除非您明确告诉它(有时用于保持代码大小)。

在编译器选项中,您可以选择是否具有Debug或Release版本以及它是静态链接还是动态链接。

静态链接将您调用的所有CRT函数的所有实际代码直接放入EXE。这对于减少所需的外部依赖项数量非常有用 - 您可以只运行EXE而不必担心是否安装了正确的xxxx.dll。缺点是您运送的CRT功能可能存在问题(安全漏洞,崩溃,竞争条件),并且最终用户解决这些问题的唯一方法是生成新的EXE。

动态链接会将引用添加到您从EXE调用的CRT函数中。当您的EXE加载并且您的代码调用引用的函数时,OS动态加载器将看到实际上,该函数在MSVCRT [D] [version] .dll中并加载该DLL,查找函数的地址然后修复代码中的引用以直接指向DLL中的函数,这样下一次,它就像你静态链接它一样快。显然,这里有一个初始启动延迟(与静态链接相比)但优势是巨大的:系统DLL由Microsoft修补,因此您可以获得问题的更新(见上文),加载的DLL是共享在内存中,所以如果你引用的DLL实际上已经被另一个进程使用了​​,那么加载它需要的时间更少,因为其他进程已经完成了很多工作。

最后,是的,像printf()和scanf()这样的CRT函数最终会与Win32 API进行对话,但并不总是与您认为的那些对话。使用Visual Studio / Windows SDK或SysInternals的“ProcExp”中的“DEPENDS”工具查看任何特定进程引入的DLL以及它们正在使用的功能。