C 运行时库第 2 部分
当我对旧问题有更多问题时,有人建议我创建新问题并参考旧问题。所以,这就是最初的问题:什么是 C 运行时库?
好的,从你的回答中,我现在得到静态链接库是 C 标准函数的 Microsoft 实现。现在:
如果我做对了,方案将如下:我想使用 printf(),所以我必须包含
它只是告诉编译器有一个函数 printf( )与这些参数。现在,当我编译代码时,因为 printf() 是在 C 标准库中定义的,并且因为 Microsoft 决定将其命名为 C 运行时库,所以它会自动从 libcmt.lib (如果在编译器中设置了 libcmt.lib)进行静态链接编译时间。我问,因为在维基百科上,在有关运行时库的文章中,运行时库是在运行时链接的,但 .lib 文件是在编译时链接的,对吗?
现在,让我困惑的是。 C 标准库有 .dll 版本。但我认为要链接 .dll 文件,您实际上必须调用 winapi 程序来加载该库。那么,如果没有静态库来提供代码告诉Windows从dll中加载所需的函数,如何动态链接这些函数呢?
关于这个主题的最后一个问题 - C 标准库函数是否也会调用 winapi,即使它们不是像更高级的 WinAPI 函数那样的 .dll 文件?我的意思是,最终要访问帧缓冲区并打印一些内容,您必须告诉 Windows 来执行此操作,因为操作系统无法让您直接操作硬件。我认为操作系统必须以相同的方式跨相似版本支持所有 C 标准库函数,因为它们是静态链接的,并且可以以不同方式支持更复杂的 WinAPI 调用,因为新版本的操作系统可以在 .dll 文件中进行调整。
I was suggested when I have some further questions on my older ones, to create newer Question and refer to old one. So, this is the original question: What is the C runtime library?
OK, from your answers, I now get thet statically linked libraries are Microsoft implementation of C standard functions. Now:
If I get it right, the scheme would be as follow: I want to use printf(), so I must include <stdio.h>
which just tells compiler there is a function printf() with these parameters. Now, when I compile code, because printf() is defined in C Standard Library, and because Microsoft decided to name it C Run Time library, it gets automatically statically linked from libcmt.lib (if libcmt.lib is set in compiler) at compile time. I ask, becouse on wikipedia, in article about runtime library there is that runtime library is linked in runtime, but .lib files are linked at compile time, am I right?
Now, what confuses me. There is .dll version of C standard library. But I thought that to link .dll file, you must actually call winapi program to load that library. So, how can be these functions dynamically linked, if there is no static library to provide code to tell Windows to load desired functions from dll?
And really last question on this subject - are C Standard library functions also calls to winapi even they are not .dll files like more advanced WinAPI functions? I mean, in the end to access framebuffer and print something you must tell Windows to do it, since OS cannot let you directly manipulate HW. I think of it like the OS must be written to support all C standard library functions same way across similiar versions, since they are statically linked, and can differently support more complex WinAPI calls becouse new version of OS can have adjustements in the .dll file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
按顺序回答您的问题:
维基百科误导了您。运行时库并不总是在运行时链接,并且在您选择静态链接的运行时(
libcmt.lib
)的情况下也不会链接。 。有一个
.dll
版本的运行时库(在运行时链接),并且编译器知道如何在.exe 文件告诉加载器在运行时加载运行时库
.dll
。这里有两个API。一是Win32 API,它是Windows操作系统本身支持的函数列表。另一个 API 是由 C 编程语言标准定义的 C 运行时 API。一些 C 运行时库函数(例如打开和读取文件)最终将调用 Win32 API 来执行实际的文件 I/O。其他 C 库函数(例如
strlen()
)不与操作系统交互,而是完全使用运行时库本身内部的代码来实现。To address your questions in order:
Wikipedia is misleading you. The runtime library is not always linked at runtime, and is not in the case where you have chosen a statically linked runtime (
libcmt.lib
).There is a
.dll
version of the runtime library (which is linked at runtime) and the compiler knows how to generate the appropriate instructions in the.exe
file to tell the loader to load the runtime library.dll
at runtime.There are two APIs here. One is the Win32 API, which is the list of functions supported by the Windows OS itself. The other API is the C runtime API which is defined by the C programming language standard. Some C runtime library functions, such as opening and reading files, will eventually make Win32 API calls to do the actual file I/O. Other C library functions, like for example
strlen()
, do not interact with the OS and are implemented using code completely inside the runtime library itself.C 运行时中的链接是“主”函数的包装器;它会初始化运行 C 代码之前所需的一切。它不包含任何“函数”,这些函数位于 C 标准库(动态链接)中。
我认为您误解了动态链接:它是由操作系统完成的。因此,您告诉操作系统您的可执行文件需要 DLL
a
、b
、c
和d
。当您执行可执行文件时,操作系统会将可执行文件加载到内存位置,并在可执行文件中读取运行它所需的内容。然后它会抓取这些 DLL 并将它们粘贴到可执行文件的内存区域中,然后它告诉您的代码a
已加载到x
、b 在
y
处加载,以便您的代码可以调用它的函数。有时,编译器在编译时包含(称为静态链接)一个库:它们这样做,这样操作系统就不必在运行时加载它,因此加载速度更快。
.lib
文件是不带“D”的 DLL 文件,因为它们可以静态链接。还可以动态链接库文件;这会使您的可执行文件更小,但会使可执行文件的加载时间更慢。关于 WinAPI:大多数对 C 库的调用都会转换为(部分)对 WinAPI 的调用;但前提是它们必须与操作系统交互(I/O 等)。不同之处在于,C 库在大多数平台上都是相同的,因此如果您使用 C 库而不是直接使用 Windows API,则会增加可移植性。
更新:
您问如果完全动态链接可执行文件如何加载 DLL?好吧:你不必! “加载 dll”和“调用加载 dll”之间的区别是;当您启动应用程序时,“加载 dll”由操作系统完成。操作系统将在您的可执行文件中搜索特定的“导入表”。它是一个表格,说明在执行之前它真正需要哪些DLL(即Windows 上的
kernel32.dll
或user32.dll
)。操作系统甚至会在代码运行之前进行“调用加载 dll”。kernel32.dll
中也存在“调用加载 dll”,供您调用代码:可以在代码运行时加载/卸载 DLL。如果您有一个巨大的代码库,并且您希望在整个应用程序生命周期(例如在启动期间)卸载一次性使用的库来释放内存,那么这可能是一种情况。如果不再使用该函数,可以卸载该 DLL。但也有可能您需要一些尚未加载的功能来加快加载速度。如果您自己需要该函数,则可以加载 DLL。这是相当高级的东西,大多数时候,操作系统无论如何都会交换掉未使用的 DLL(“删除”内存,字面意思是:它将不常用的内存(如未使用的 DLL)移动到一个大的地方存储,例如硬盘,如果您需要它,它会自动将其“交换”回来!)。因此:您不必太关心 Windows 上加载/卸载 DLL 的问题。如果您有一个好的链接器,并告诉它动态链接库,那么一切都会很好。
The linked in C Run Time is a wrapper around your "main" function; it initializes everything that is needed before your C code can be run. It does not contain (m)any "functions", those are in the C standard library (which is dynamically linked).
I think you misunderstand dynamic linking: it's done by the OS. So you tell the OS that your executable needs DLL
a
,b
,c
andd
. The time you execute your executable, the OS will load the executable in a memory location, and reads in the executable what is necessary to run it. It will then grab those DLLs and paste them in the memory region of your executable, and then it tells your code thata
is loaded atx
,b
is loaded aty
, etc. so your code can call it's functions.Sometimes, compilers include (called statical linking) a library at compile-time: they do that, such that the OS doesn't have to load it at runtime, and thus loads faster.
.lib
files are DLL files without the "D", because they can be statically linked. It's also possible to dynamically link against library files; this makes your executable smaller, but makes load time of your executable slower.About the WinAPI: most calls to the C library are converted into (some) calls into the WinAPI; but only if they have to interact with the OS (I/O, etc.). The difference is that the C library is equal on most platforms, so it increases portability if you use the C library instead of the Windows API's directly.
Update:
You asked how to load a DLL if you completely dynamically link your executable? Well: you don't have to! The difference between the "load dll" and "call to load dll" is; the "load dll" is done by the OS when you launch the application. The OS will search your executable for a specific "import table". It's a table stating which DLLs it really needs, before it can execute (i.e.
kernel32.dll
oruser32.dll
on Windows). The OS will make the "call to load dll", even before your code runs.The "call to load dll" also exists in
kernel32.dll
for your code to be called: it's possible to load/unload DLLs while your code runs. This can be of a case, if you have a huge code-base and you want to free memory by unloading that one-time use library during your whole application lifetime (for instance, during startup). If you don't use the function anymore, you can unload the DLL. But it's also possible that you need some function, which you haven't loaded yet, to speed up loading. You can then load the DLL if you need the function yourself. This is quite advanced stuff, and most of the time, the OS will swap away the unused DLLs anyway ("removing" memory, literally: it moves the memory that isn't used much (like an unused DLL) to a place of mass storage, like the harddisk. If you need it, it automatically "swaps" it back!).So: you don't have to concern much about loading/unloading DLLs on Windows. If you have a good linker, and tell it to dynamically link against libraries, it will all work out just fine.
在 Visual C++ 和其他一些编译器中,CRT 会为您链接进来,除非您明确告诉它不要这样做(有时对于减少代码大小很有用)。
在编译器选项中,您可以选择是使用调试版本还是发布版本,以及是静态链接还是动态链接。
静态链接将您调用的所有 CRT 函数的所有实际代码直接放入 EXE 中。这对于减少所需的外部依赖项很有用 - 您只需运行 EXE,而不必担心是否安装了正确的 xxxx.dll。缺点是您提供的 CRT 函数可能存在问题(安全漏洞、崩溃、竞争条件),而您的最终用户解决这些问题的唯一方法是您生成一个新的 EXE。
动态链接为您从 EXE 调用的 CRT 函数提供引用。当您的 EXE 加载并且代码调用引用的函数时,操作系统动态加载器实际上会看到该函数位于 MSVCRT[D][version].dll 中,然后加载该 DLL,查找该函数的地址然后修复代码中的引用以直接指向 DLL 中的函数,这样下次就可以像静态链接它一样快。显然,这里有一个初始启动延迟(与静态链接相比),但优点是巨大的:系统 DLL 已由 Microsoft 修补,因此您可以获得问题的更新(见上文),加载的 DLL 是共享在内存中,因此如果您引用的 DLL 实际上已被另一个进程使用,则加载它所需的时间会更少,因为其他进程已经完成了大量工作。
最后,是的,像 printf() 和 scanf() 这样的 CRT 函数最终确实会与 Win32 API 进行交互,但并不总是您所认为的那样。使用 Visual Studio/Windows SDK 中的“DEPENDS”工具或 SysInternals 的“ProcExp”来查看任何特定进程提取了哪些 DLL 以及它们正在使用哪些函数。
In Visual C++ and some other compilers, the CRT is linked in for you, unless you explicitly tell it not to (sometimes useful for keeping code size down).
In the compiler options, you can choose whether to have the Debug or Release versions and whether its' statically linked or dynamically.
Static linking puts all the actual code from all the CRT functions you call directly into your EXE. This is useful for reducing how many external dependencies you require - you can just run the EXE and no worry about whether you have the right xxxx.dll installed. The disadvantage is that the CRT functions you shipped might have problems (security exploits, crashes, race conditions) and the only way your end user can fix these problems is if you produce a new EXE.
Dynamic linking puts a reference to the CRT functions you call from your EXE. When your EXE loads and your code makes a call to a referenced function, the OS dynamic loader will see that actually, that function is in MSVCRT[D][version].dll and go load that DLL, look up the address of the function and then fixup the reference in your code to point directly to the function in the DLL, so that next time, it is as fast as if you'd statically linked it. Clearly, there's an initial startup delay here (compared to static link) but the advantages are enormous: system DLL's get patched by Microsoft, so you can get updates to problems (see above), loaded DLL's are shared in memory, so if a DLL you reference is actually already used by another process, it takes less time to load it up as the other process did a lot of the work already.
Finally, yes, the CRT functions like printf() and scanf() do eventually talk to Win32 API's, but not always the ones that you think. Use the 'DEPENDS' tool in Visual Studio/Windows SDK or SysInternals 'ProcExp' to see which DLL's are pulled in by any particular process and what functions they are using.