C++学习(二)静态链接库和动态链接库、Debug和Release、VS项目类型

来源于网络,供自己参考学习,如有问题,欢迎指正!

一、库的概念

1、库是什么

  库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库。
  所谓程序库,一般是软件作者为了发布方便、替换方便或二次开发目的,而发布的一组可以单独与应用程序进行compile time或runtime链接的二进制可重定位目标码文件。通俗一点说,所谓一个库,就是一个文件,这个文件可以在编译时由编译器直接链接到可执行程序中,也可以在运行时由操作系统的runtime enviroment根据需要动态加载到内存中。一组库,就形成了一个发布包,当然,具体发布多少个库,完全由库提供商自己决定。
  本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指链接。
  一个程序编译成可执行程序的步骤如下:

请添加图片描述

(1)库中的头文件(.h)和库文件(.lib)和动态链接库文件(.dll)

  .h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的。
  头文件中有函数的申明,库文件实现函数的定义。头文件提供的是一个函数的声明,并没有这个函数具体代码,而库就是存放这个函数的具体实现代码。头文件包含声明,库文件包含实现或者与动态库的链接。
  在自己生成库文件时,如果生成了DLL,则肯定也生成 LIB文件,如果要完成源代码的编译和链接,有头文件和lib就够了。如果生成静态库文件,则没有DLL ,只有lib,这时函数可执行代码部分也在lib文件中。

动态链接库: 包含.h文、.lib文件(动态链接库的导入库文件)和.dll文件。
静态链接库: 包含.h文、.lib文件(静态链接库文件)。

  • .h文件: 声明函数接口
  • .dll文件: 函数可执行代码
  • .lib文件(按照动态库和静态库分为两类):
    • 静态链接库(Static Libary): 静态库本身就包含了实际执行代码、符号表等等,在程序编译时函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件。
    • 动态链接库的导入库(Import Libary): 其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。简单来说就是告诉链接器调用的函数在哪个DLL中,函数执行代码在DLL中的什么位置。

下图是博客园博主骏骏总结的库文件组成的内容:文章链接
在这里插入图片描述

(2)静态链接库

  之所以称为静态库,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结:

  • 静态库对函数库的链接是放在编译时期完成的。
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

静态库包含.h文件和.lib文件,一般在Visiual Studio中按下面方面使用:

  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “C/C++” ⟶ \longrightarrow ” 常规” ⟶ \longrightarrow ” 附加包含目录”,输入头文件存放目录。作用是寻找#include<xxxx.h>中的xxxx.h的搜索目录(每一项对应一个文件夹XXXX,文件夹中包含了编译时所需的头文件,使用时直接#include即可。
  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “链接器” ⟶ \longrightarrow ”常规 ⟶ \longrightarrow ” 附加库目录”,输入静态库所在目录(lib文件存放目录)。当你用 #pragma comment(lib,“a.lib”)的时候;此时就搜索a.lib的路径列表就包含这个路径。
  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “链接器” ⟶ \longrightarrow ”输入” ⟶ \longrightarrow ”附加依赖项”,输入静态库名(所有lib文件的文件名)。比如某个.LIB文件a.lib,添加到附加依赖项,你的LIB文件被真正包含进来了,等同于“#pragma comment(lib, “winsock.lib”) ”语句。

(3)动态链接库

  使用动态库的原因:

  • 静态库的特点导致空间浪费是静态库的一个问题。
  • 静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。

  动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。动态库特点总结:

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单。
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

动态库包含.h文件、.lib文件和.dll文件,一般在Visiual Studio中按下面方面使用:

  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “C/C++” ⟶ \longrightarrow ” 常规” ⟶ \longrightarrow ” 附加包含目录”,输入头文件存放目录。
  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “链接器” ⟶ \longrightarrow ”常规 ⟶ \longrightarrow ” 附加库目录”,输入导入库文件所在目录(lib文件存放目录)。
  • “属性面板” ⟶ \longrightarrow ”配置属性” ⟶ \longrightarrow “链接器” ⟶ \longrightarrow ”输入” ⟶ \longrightarrow ”附加依赖项”,输入静态库名(所有lib文件的文件名)。
  • 当需要向项目中添加.dll动态链接库时,直接将需要添加的.dll文件拖拽到项目生成的.exe所在的文件夹下即可。(当然一般下载安装好第三方库后,可以首先配置环境变量,以便使用到该库的动态链接库dll的程序能在该计算机上正确运行而不用再复制dll。(个人猜测,还没有验证,因为项目文件生成的可执行文件.exe在运行时肯定会去找的环境变量中的库目录))

2、Visual Studio C++工程中库的配置注意事项

  在Visual Studio C++工程中配置库的时候,一般需要将库的头文件路径和库文件路径配置进去,这其中有几个比较容易混淆的概念:包含目录、附加包含目录、库目录、附加库目录

头文件包含路径: VC++目录->包含目录 或者 C/C++ -> 常规 -> 附加包含目录
库文件路径:   VC++目录->库目录 或者 链接器 ->常规 -> 附加库目录

  他们的区别是主要是在于编译器的寻找顺序不同,一般使用C/C++和链接器下面的设置,不建议使用VC++目录下面的设置。
  VC++目录下面的设置将搜索源代码文件中引用的包含文件的目录,对应于环境变量对应于环境变量include,是全局的,需要提前配置环境变量,从全局变量中的路径去搜索;附加包含目录用于当前项目,添加到搜索包含文件的目录列表中的目录。

  由此可知包含目录和附加包含目录(库目录和附加库目录)的区别主要在于全局还是当前,那么当需要对某工程添加这些目录时,通常情况下,都是在附加包含目录和附加库目录中添加的。

还有种简单的调用库的方法,相比上面配置方式简化:

  如果是静态库和头文件,把静态库拷贝到自己项目中的一个目录,然后将该目录添加为附加依赖项目录,然后设置引用该静态库,将头文件拷贝到自己的项目中,在需要的地方#include头文件。
  如果是动态库和头文件,只比静态库和头文件多一步,就是将动态库拷贝到自己exe的所在目录中。

3、动态库的显式调用与隐式调用

  上面刚刚提到的动态库使用方法和静态库基本一样,都属于是隐式调用,编译的时候指定相应的库和查找路径,除此之外,C++动态库还可以显式调用,和隐式调用动态链接库不同,在 C/C++ 程序中显示调用动态链接库时,无需引入和动态链接库相关的头文件。windows下的显式调用,需要用到window的API,Linux下也可以显式调用动态库。
  不过“显式”使用C++动态库中的Class是非常繁琐和危险的事情,因此能用“隐式”就不要用“显式”,能静态就不要用动态。这里不再细说。

4、一种新的C++库的管理方法Vcpkg

  vcpkg 是适用于 C/C++ 库的跨平台命令行包管理器,由 C++ 团队使用 C++ 开发的。它简化了 Windows、Linux 和 macOS 上第三方库的安装,同时支持开源库和专有库。vcpkg 目录中的库与 VS2017/VS2019兼容。
  他有很多优点,对于windows编程C++的同学来说,它的最好用的用处是无缝集成Visual Studio,不管动态库还是静态库,不需要设置库文件、头文件的所在目录,自动一键集成。

详细了解可以查看以下链接:
vcpkg:跨平台 C++ 包管理器的安装教程
Visual Studio开源库集成器Vcpkg全教程–利用Vcpkg轻松集成开源第三方库
vcpkg的github项目

二、C++的Debug和Release

1、区别

  Debug:调试版本,包含调试信息,所以容量比Release大很多,并且不进行任何优化(优化会使调试复杂化,因为源代码和生成的指令间关系会更复杂),便于程序员调试。Debug模式下生成两个文件,除了.exe或.dll文件外,还有一个.pdb文件,该文件记录了代码中断点等调试信息
  Release:发布版本,不对源代码进行调试,编译时对应用程序的速度进行优化,使得程序在代码大小和运行速度上都是最优的。(调试信息可在单独的PDB文件中生成)。Release模式下生成一个文件.exe或.dll文件

2、vc++编译时运行库选择(/MT、/MTd、/MD、/MDd)

MT:mutithread,多线程库,编译器会从运行时库里面选择多线程静态连接库来解释程序中的代码,即连接LIBCMT.lib库
MTd:mutithread+debug,多线程调试版,连接LIBMITD.lib库
MD:MT+DLL,多线程动态库,连接MSVCRT.lib库,这是个导入库,对应动态库为MSVCRT.dll
MDd: MT+DLL+debug,多线程动态调试库,连接MSVCRTD.lib库,对应动态库为MSVCRTD.dll

  开发多线程程序时(单线程本文不做讨论),需要选择MT、MTd、MD、MDd其中的一个。对于MT/MTd,由于连接运行时库是LIBCMT.lib/LIBCMTD.lib,这两个库是静态库,所以此种方式编译的程序,移到另一台机器上面也可以正常运行。但是对于MD/MDd,连接的是动态库,所以如果另一台机器上没有MSVCRT.dll/MSVCRTD.dll时,就提示缺少动态库这样的错误。

三、VS项目区别(c++)

  因为64位处理器向下兼容32位操作系统系统及应用程序,所以32位的程序拿到64位机器上编译一下就成64们的程序了。win 32 API在进入64位后,绝大多数API中,如果没有特别说明,只有一种基本数据类型发生了改变,那就是指针:有原来的4个字节大小变为8个字节。其他基本数据类型的内存大小都维持不变。 这对于原来使用sizeof的代码可以完全不用修改编译成64位直接运行。但有些程序逻辑会有问题,比如在32为下,某个高位的指针值是非法指针,到了64位之后就不是了。有些程序假设指针永远是4个字节,并进行指针运算。
  windows提供win32 API以供程序员完成各种操作,所以控制台,win32,mfc都可直接调用win32 API。但直接使用win32 API,用代码完成诸如创建窗口,显示窗口等操作太过繁杂,于是我们把这些代码结合抽取出来,变成OOP中的类,也就是微软基础类库(MFC)
  Win32 API函数是Windows的核心,比如我们看到的窗体、按钮、对话框什么的,都是依靠Win32函数“画”在屏幕上的,由于这些控件(有时也称组件)都 用于用户与Windows进行交互,所以控制这些控件的Win32 API函数称为“用户界面”函数(User Interface Win32 API),简称UI函数;还有一些函数,并不用于交互,比如管理当前系统正在运行的进程、硬件系统状态的监视等等……这些函数只有一套,但是可以被所有的 Windows程序调用(只要这个程序的权限足够高),简而言之,API是为程序所共享的。

请添加图片描述

1、控制台应用(常见的也叫:Win32控制台应用)

  没有界面,只有命令符。生成的“.exe”文件直接运行操作即可。
  win32控制台项目指在32位Windows命令提示符(即所谓的dos)环境下运行的应用程序。初始代码模版以main为程序入口,默认情况下,只链接C++运行时库和一些核心的win32库,链接器subsystem参数为console类型,所以编译出来的程序会有黑色的控制台窗口作为呈现标准输入(std::in)和标准输出(std::out)

请添加图片描述

2、空项目

  啥都没有,因为空工程不包含任何的源代码文件,接下来你只需要在相应的源代码文件夹和头文件文件夹加入相应的.cpp和.h文件即可。

3、windows桌面应用程序(Win32项目)

  有界面。但是界面里面的控件,基本上要自己去实现。
  初始代码模版实现一个简单的windows窗口,以WinMain作为程序入口,引用了win32Api头文件和库,链接器subsystem参数为windows,编译出来会有一个简单的窗口。可以diy,如下图:

请添加图片描述

4、MFC应用

  也有界面,但界面里的控件不需要自己去实现了,常用的控件都已经在MFC库内写好,直接拖动即可。
  本质上是个win32工程,只是默认帮你引用了mfc框架的头文件和库,并且程序入口由mfc框架提供,不需要自己写。

请添加图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值