IE盒子

搜索
查看: 130|回复: 0

Windows 中的 C/C++ 编程环境(一)

[复制链接]

2

主题

6

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2023-1-9 17:03:14 | 显示全部楼层 |阅读模式
Visual Studio 是一个巨无霸,包含了非常多的编译、调试工具和图形界面等,在这里梳理一下安装 Visual Studio 并勾选桌面C++组件之后,电脑上到底“安装”了哪些东西,以及 C/C++ 程序如何调用相关的库。
一张图总结


Windows SDK

安装Visual Studio会附带安装Windows SDK,在另外一篇文章中有关于Windows SDK的简介。
Windows SDK 的安装路径一般是 C:\xxx\Windows Kits\10



Win10 SDK

这个路径下包含bin, Redist, Include, Lib, Source 等,依次进去看看有什么。
SDK -- bin

bin一般用来存放各种二进制工具,以这里的 bin\xxx\x86为例,这个路径下包含了很多32位的工具、动态库和vbs脚本等。这些文件中的大部分只跟Windows开发相关,跟标准 C/C++开发无关。
可以看到一个动态库 bin\xxx\x86\ucrt\ucrtbased.dll
ucrt 表示 universal C runtime 运行时,universal 表示它可以同时适用于 C 和 C++ 开发,结尾的 "d" 可能代表"debug",用everything 搜索一下,发现相同的文件还出现在另外的含有"Debug"的路径下,文件路径表明它确实是 debug 版本的动态库,验证了猜想。


去掉 debug 标记,搜索 "ucrtbase.dll",发现release版本也出现在 VS 路径下。


同时可以发现,"ucrtbased.dll" 和 "ucrtbase.dll" 都出现在系统目录 C:Windows\System32 以及 C:\Windows\SysWOW64 下,分别对应于64位和32位的版本。
用 dependency walker 查看一下,发现这个dll 中包含了 C 标准库中的函数实现,另外还有一些以下划线开头的函数,从函数名可以猜测它们是 msvc 在实现 C 标准库函数时用到的一些中间函数。



ucrtbase.dll中的C标准库函数



ucrtbase.dll中的中间辅助函数

SDK -- Redist

Redist 表示 "redistributable",一般用来存放 release 版的 dll库,进入 C:\Windows Kits\10\Redist 发现的确如此


其中最大的文件是 ucrtbase.dll,它正是 ucrtbased.dll 对应的 release 版本。这个目录下还有两类 dll 文件,第一类是 api-ms-win-core-xxx.dll,第二类是 api-ms-win-crt-xxx.dll。这些 dll 文件的命名看起来有些奇怪,都是以类似于 l1-1-0 的表达式结尾。
api-ms-win-crt-xxx.dll 中是一些特定功能的 C 标准库函数集合,并且把这些函数重定向到 ucrtbase.dll。api-ms-win-crt-xxx.dll 中并没有给出这些函数的定义!所以用 IDA pro 或者 010 Editor 打开这类 dll 可能会因为无法识别而报错。
类似地,api-ms-win-core-xxx.dll 把一些 Win32 API 函数重定向到 kernel32.dll 等库中。




SDK -- Include

Include 路径下会存放c/c++头文件


ucrt中包含 C 标准库头文件,如 stdio.h, math.h 等。ucrt 还包含了微软实现的 C/C++ 运行时头文件,以 "corecrt_" 开头,(表示core c runtime)例如 corecrt_io.h, corecrt_math.h 等。corecrt_xxx.h 头文件中会用 #if 判断分别处理 C 和 C++ 环境。
同时可以发现,ucrtbase.dll 中包含的那些以下划线开头的函数,正好在 corecrt_xxx.h 头文件中被声明过。所以基本可以确认,ucrt 中函数的实现放在 ucrtbase.dll 库中。
Include 路径下还有一个 um 文件夹,里面有上千个 .h 文件,随便打开一个,发现这里对 Win32 API 中的函数进行了声明。在进行 Windows 编程时,#include Windows.h 会通过一系列的中间文件最后 include 这里的函数声明。


SDK -- Lib

在 Lib 路径下也可以看到对应的 ucrt,其中包括了 ucrt 的静态库和动态连接lib文件,从文件大小很容易分辨。可以猜测,静态库 libucrt.lib 中包含对应于 ucrt 头文件中的函数实现,ucrt.lib 则被用来链接上文提到的 ucrtbase.dll。


用 IDA pro 可以看到, ucrt.lib 仅仅包含了所有的 api-ms-win-crt-xxx.dll 的一些信息,C 程序可以通过 ucrt.lib  动态链接到 api-ms-win-crt-xxx.dll,其中的 C 标准库函数会被重定向到 ucrtbase.dll 中特定的位置,因为 ucrtbase.dll 在程序运行时已经被加载到进程内存中了,主程序可以调用其中的函数。
继续用 IDA pro 查看 libucrt.lib,发现它确实是静态库,里面包含了很多 obj 文件,obj 文件的文件名正好跟 C:\Windows Kits\10\Source\10.0.19041.0\ucrt  中的 cpp 文件名一致,可以猜测 libucrt.lib 就是用 Source 中的源文件生成的。




Lib中还包含一个 um 文件夹,这里面是跟 Windows编程相关的各种 .lib 文件,比如 kernel32.lib, user32.lib, gdi32.lib 就放在 um 路径下,它们分别是动态链接到 kernel32.dll, user32.dll 和 gdi32.dll 所需要的lib文件。



总结


  • Windows SDK 中包含了 C 语言的标准库头文件以及静态和动态链接库。
头文件放在
C:\Windows Kits\10\Include\10.0.19041.0\ucrt
静态链接:
debug 模式,链接 C:\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86\libucrtd.lib
release 模式,链接 C:\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86\libucrt.lib
动态链接:
debug 模式,链接 C:\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86\ucrt.lib
release 模式,链接 C:\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86\ucrtd.lib
相应的标准库 ucrtbase.dll 文件存放在系统目录 C:Windows\System32 下。

2. Windows SDK 中还包含了使用 Win32 API 需要的头文件以及动态链接库。
头文件放在
C:\Windows Kits\10\Include\10.0.19041.0\um
动态库 kernel32.dll, gdi32.dll 等放在系统目录 C:Windows\System32\SysWOW64 下
链接动态库需要的 lib文件放在 C:\Windows Kits\10\Lib\10.0.19041.0\um\x86 下。

3. ucrtbase.dll 和 kernel32.dll等动态库存放在系统目录,程序运行时会自动加载到进程的内存。C程序会通过一些中间dll 重定向到 ucrtbase.dll。搜到一个关于中间 dll 的介绍,以后再研究。



后续文章中补充了 C/C++ 程序运行时库的详细介绍。
编译一个 C 程序需要链接跟运行时相关的三个部分。第一个是 ucrt, 提供 C 标准库函数。第二个是 vcruntime, 第三个部分是 CRT initialization。这三部分都提供了某些运行时的处理,ucrt 和 vcruntime 可以选择静态或者动态链接,第三个只能动态链接,具体链接那个库依赖于前两者的链接方式是静态还是动态。C++ 程序还需要链接 msvcp140.dll 运行时库。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表