一、C\C++ 运行时库编译选项简单说明

问题:我的dll别人没法用

运行时库是个很复杂的东西,作为开发过程中dll制作需要了解的一部分,这里主要简单介绍一下如何选择编译选项。

在我们的开发过程中时常会遇到这样的问题:

1. 我的VS版本比较高(比如:VS2012),我想制作一个dll,封装了几个函数给别人用。

2. 打包后发现我的dll引用了msvcr110.dll或者msvcr110d.dll,这个dll别人电脑可能没有。

3. 于是别人使用时出现了诸如:“无法在DLL“XXXX.dll”中找到名为“XXXX()”的入口点”等问题。

最终结果就是,反复检查发现都没有错,用工具查看也发现函数确实已经导出了,但是别人就没法用。

这里可能就需要对编译选项进行修改了。

解释:如何避免上述问题

在VS中打开:项目属性——>配置属性——>C/C++——>代码生成——>运行时。其中可以看到多个选项,如下图所示:

在微软的msdn中对CRT库进行了简单解释:

https://msdn.microsoft.com/zh-cn/library/2kzt1wy3(VS.80).aspx

https://msdn.microsoft.com/zh-cn/library/abx4dbyh(v=vs.110).aspx

下面是我黏贴的表格:

选项 说明
/MD

使应用程序使用运行时库的多线程并特定于 DLL 的版本。定义 _MT_DLL,并使编译器将库名 MSVCRT.lib 放入 .obj 文件中。

用此选项编译的应用程序静态链接到 MSVCRT.lib。该库提供允许链接器解析外部引用的代码层。实际工作代码包含在 MSVCR80.DLL 中,该库必须在运行时对于与 MSVCRT.lib 链接的应用程序可用。

当在定义了 _STATIC_CPPLIB (/D_STATIC_CPPLIB) 的情况下使用 /MD 时,它将导致应用程序与静态多线程标准 C++ 库 (libcpmt.lib) 而非动态版本 (msvcprt.lib) 链接,同时仍通过 msvcrt.lib 动态链接到主 CRT。

/MDd 定义 _DEBUG_MT_DLL,并使应用程序使用运行时库的调试多线程并特定于 DLL 的版本。它还使编译器将库名 MSVCRTD.lib 放入 .obj 文件中。
/MT 使应用程序使用运行时库的多线程静态版本。定义 _MT 并使编译器将库名 LIBCMT.lib 放入 .obj 文件中,以便链接器使用 LIBCMT.lib 解析外部符号。
/MTd 定义 _DEBUG_MT。此选项还使编译器将库名 LIBCMTD.lib 放入 .obj 文件中,以便链接器使用 LIBCMTD.lib 解析外部符号。
/LD

创建 DLL。

将 /DLL 选项传递到链接器。链接器查找 DllMain 函数,但并不需要该函数。如果没有编写 DllMain 函数,链接器将插入返回 TRUE 的DllMain 函数。

链接 DLL 启动代码。

如果命令行上未指定导出 (.exp) 文件,则创建导入库 (.lib);将导入库链接到调用您的 DLL 的应用程序。

/Fe(命名 EXE 文件)解释为命名 DLL 而不是 .exe 文件;默认程序名成为 basename.dll 而不是 basename.exe。

除非显式指定 /MD,否则将暗指 /MT

/LDd

  创建调试 DLL。定义 _MT_DEBUG

就从VS的dll库的编译选项来说就前面四项,/MD、/MDd、/MT和/MTd。其中/MDd、/MTd后面的“d”表示编译生成的是Debug版本,也就是用于编译生成Debug版本的程序;不加“d”表示是Release版本的程序,如果此时你把项目配置成Debug版本,编译会不通过。

动态链接多线程库(MD/MDd)

动态链接的运行时库,此时将msvcrt.lib安置到obj文件中,它连接到dll的方式是静态链接,实际上工作的库是msvcrxx.dll。所有的 C 库函数保存在动态链接库 msvcrXX.dll中, 由msvcrXX.dll处理多线程问题。也就是说,这种编译方式下我们是通过msvcrXX.dll这个动态链接库去链接CRT。

此时我们编译的dll引用了msvcrXX.dll文件,这个文件在使用的时候必须能够被计算机查询到。比如:我的电脑编译引用了msvcr110.dll,那么我的dll给别人调用的时候,对方计算机一定要有msvcr110.dll,否则dll库就无法使用。因此这种编译方式,必须将msvcr110.dll一同携带过去,并且要在对方计算机上进行注册。

使用此方式编译时,使用Depends查看,我们可以看到dll 引用了msvcr110.dll,如下图:

 

静态链接多线程库(MT/MTd)

静态链接多线程库,此时编译器把LIBCMT.lib 安置到OBJ文件中,让链接器使用LIBCMT.lib 处理外部符号。这种方式说简单点就是让我们的dll能够直接链接到CRT,无需引用msvcrXX.dll这个动态链接库。这样我们就不需要担心对方电脑是否拥有对应版本的msvcrXX.dll,因此这是一种方便的好办法。

在这种方式下,编译的dll通过Depends查看就是这样的:

注意:几个注意点

光从上面来看,MT的方式很好用,但是必须要注意一个问题:

不要混合使用库的静态版本和动态版本。在一个进程中有多个库副本会导致问题,因为副本中的静态数据不与其他副本共享。(还应该避免在一个进程中混合使用这些库的调试版本和非调试版本)。

还有,在实际使用中能用MD就用MD的方式,因为这种方式软件更小,调用同一个dll时在内存中使用的是同一个副本。这就不会有堆空间释放问题:

不同的模块各自有一份C运行时库代码,各个C运行库会有各自的堆,导致了各个模块会有各自的堆。如果在A堆中申请空间,到B堆中释放就会有崩溃,在模块A申请的空间,必须在模块A中释放。

 

二、函数调用方式_cdecl与_stdcall的选择

_stdcall调用

 

_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。形式如下:

#define SW_REV extern "C" _declspec(dllexport)

SW_REV int __stdcall add(int a, int b);

int  __stdcall add(int a, int b)
{
return a+b;
}

 

_cdecl调用

_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。

在不加修饰的情况下,VC++默认使用这种调用方式,形式如下(默认,可省略):

#define SW_REV extern "C" _declspec(dllexport)

SW_REV int add(int a, int b);

int add(int a, int b)
{
return a+b;
}

什么时候区分?

其实两种方式都一样,区别在于调用。例如:有些语言要求调用时只认_stdcall,那么就只能按照要求使用_stdcall版本的dll。很多情况下,调用方式都可选择,说白了,就是一定要保持一致,例如C#调用上述_stdcall方式的dll:

[DllImport("SwLib.dll", EntryPoint = "add", CallingConvention = CallingConvention.StdCall)]
private static extern int add(int a, int b);

这里CallingConvention需要选择CallingConvention.StdCall,如果我将其改成 CallingConvention.Cdecl,程序就会报错,指出堆栈调用不对称:

 

PS:写这个东西真的好费劲,上次写到现在好久了,有好多想记录一下的东西,发现自己懒得写,好懒!

制作C/C++动态链接库(dll)若干注意事项的更多相关文章

  1. VC++动态链接库(DLL)编程深入浅出(zz)

    VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...

  2. 动态链接库dll,静态链接库lib, 导入库lib

    转载地址:http://www.cnblogs.com/chio/archive/2008/08/05/1261296.html 目前以lib后缀的库有两种,一种为静态链接库(Static Libar ...

  3. 动态链接库dll,导入库lib,静态链接库lib

    目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库” ...

  4. 动态链接库DLL导出函数并导入使用

    动态链接库DLL导出函数并导入使用 本文完全参考自<vs2008制作dll笔记,回带值样例>. 首先制作DLL文件,在vs2010中新建Win32控制台项目,选择DLL选项,简历头文件,源 ...

  5. ASP.net/C#中如何调用动态链接库DLL

    动态链接库(也称为DLL,即为“Dynamic Link Library”的缩写)是Microsoft Windows最重要的组成要素之一,打开Windows系统文件夹,你会发现文件夹中有很多DLL文 ...

  6. VC++动态链接库(DLL)编程深入浅出(转帖:基础班)

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...

  7. VC-基础:VC++动态链接库(DLL)编程深入浅出

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...

  8. 编译可供C#调用的C/C++动态链接库dll文件

    编译可供C#调用的C/C++动态链接库dll文件,C语言控制台应用程序,探索生成dll过程 由于项目需求,需要公司另一个团队提供相关算法支持,是用C语言编译好的dll库提供给我们进行调用. 但是拿到d ...

  9. VS2010编写动态链接库DLL及单元测试用例,调用DLL测试正确性

    转自:http://blog.csdn.net/testcs_dn/article/details/27237509 本文将创建一个简单的动态链接库,并编写一个控制台应用程序使用该动态链接库,该动态链 ...

  10. 无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败。

    无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败. 在Asp.Net项目中使用WebClient或HttpWebRequest时出现以上错误 解决方案:把以下代码放在 ...

随机推荐

  1. Min Stack [LeetCode 155]

    1- 问题描述 Design a stack that supports push, pop, top, and retrieving the minimum element in constant ...

  2. CentOS6.5 python 2.6升级到2.7

    在CentOS6.5下,将自带的python2.6.6升级到python2.7.3,解决方法如下: 下载python2.7.3包,并解压缩,输入命令:#wget http://python.org/f ...

  3. Jquery动画效果--地铁站名指示等效果

    源码参考:源码爱好者--jQuery仿地铁线路指示灯效果,经修改和美化,特此记录一下. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tra ...

  4. 第一章:1-06、 试将TCP/IP和OSI的体系结构进行比较。讨论其异同之处?

    <计算机网络>谢希仁著第四版课后习题答案答:(1)OSI和TCP/IP的相同点是二者均采用层次结构,而且都是按功能分层.(2)OSI和TCP/IP的不同点:①OSI分七层,自下而上分为物理 ...

  5. 实例化新的一个(new)

    今天越到了一个特别尴尬的问题,其实特别简单就一句代码的事. PlayList pModel = new PlayList(); foreach (XmlNode xn1 in xnl) { ····· ...

  6. MHA学习笔记

    MHA是一款开源的MySQL高可用程序,为MySQL主从复制架构提供了节点故障转移功能,当 master发生故障时MHA会自动提升拥有最新数据的slave节点成为新的主节点,还提供了master节 点 ...

  7. php异常处理示例

    php异常处理使用示例,代码说明了普通错误和致命错误捕获及处理的方法.  代码如下: <?php //禁止错误输出 error_reporting(0); //设置错误处理器 set_error ...

  8. C++判断五位以内的对称素数

    题目内容:判断一个数是否为对称且不大于五位数的素数. 输入描述:输入数据含有不多于50个的正整数n(0<n<232). 输出描述:对于每个n,如果该数是不大于五位数的对称素数,则输出“Ye ...

  9. 利用FMX控件的MakeScreenshot过程实现WAIT效果

    原理: 1.新建一个waitform,添加控件: 背景图片BACKPIC:Timage控件: 再叠加一个WAIT图标(TAniIndicato控件). 2.在要实现wait效果的form上添加一个控件 ...

  10. 相比于汇编语言的准确性c语言延时精确度如何提升

    只要合理的运用,C还是可以达到意想不到的效果.很多朋友抱怨C效率比汇编差了很多,其实如果对Keil C的编译原理有一个较深入的理解,是可以通过恰当的语法运用,让生成的C代码达到最优化.即使这看起来不大 ...