【转】extern “C“和__declspec(dllexport)以及__declspec(dllimport) 和def的简单解析

转自:https://blog.csdn.net/xupan_jsj/article/details/9028759

前面的extern "C"  __declspec(dllexport)  __declspec(dllimport)都是用于函数或者变量,甚至类的声明的(可以把extern "C"放在class的前面,但是编译器会忽略掉,最后产生的还是C++修饰符,而不是C修饰符)这样的用法有个好处就是下面的代码可以在混有类的函数和变量上使用下面的宏,虽然对类不起作用:

#ifdef __cplusplus
extern "C"
{
#endif
 
//函数声明
//变量声明,变量一般前面都有extern
//类声明,这个不起作用,编译器直接忽略掉class前面的extern “C”
#ifdef __cplusplus
}
#endif

C 和C++ 对应不同的调用约定,产生的修饰符也各不相同,如下:

调用约定extern "C" 或 .c 文件.cpp、.cxx 或 /TP

C 命名约定 (__cdecl)

_test

?test@@ZAXXZ

Fastcall 命名约定 (__fastcall)

@test@0

?test@@YIXXZ

标准调用命名约定 (__stdcall)

_test@0

?test@@YGXXZ


__declspec(dllexport)  __declspec(dllimport)一般也是使用宏的形式:

#ifdef ONEDLL_EXPORTS
#define ONEDLL_API __declspec(dllexport)
#else
#define ONEDLL_API __declspec(dllimport)
#endif

这样在DLL代码本身就是__declspec(dllexport) ,在使用DLL的程序中就变成了__declspec(dllimport),这两标志分别用来指明当前的函数将被导出,和当前函数是被导入的。
 

上面的两个宏结合一下就是下面这样的了:

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 ONEDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// ONEDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef ONEDLL_EXPORTS
#define ONEDLL_API __declspec(dllexport)
#else
#define ONEDLL_API __declspec(dllimport)
#endif

// 此类是从 OneDll.dll 导出的
#ifdef __cplusplus
extern "C"
 {
#endif
class ONEDLL_API COneDll {
public:
    COneDll(void);
    ~COneDll(void);
    
    // TODO: 在此添加您的方法。
    int m_a;
    int m_b;
    int *m_p;
    int m_n;

    void AddValue();

};

extern ONEDLL_API int nOneDll;

ONEDLL_API int fnOneDll(void);

#ifdef __cplusplus
}
#endif


如果调用模块和被调用模块都是C++(而且是同一种编成环境,如VC,甚至需要同一版本的VC),那么就不需要extern “C”了,因为这个标志的作用就是用在函数和变量声明前,无论是调用模块,还是被调用模块,都将生成C修饰符,调用模块将需要C修饰符的函数,而被调用模块将产生C修饰符的函数,所以这个标志在两者都是C++的时候使用并不受影响,不使用这个标志,也不受影响。
但是如果C模块要调用C++ 模块,那么C++模块就需要使用extern “C”,当然C不用,由于是在头文件的声明中使用,所以使用下面的宏能够使得这个头文件也在C中顺利使用:

#ifdef __cplusplus
extern "C"
 {
//函数声明
//变量声明,变量一般前面都有extern
//类声明,这个不起作用,编译器直接忽略掉class前面的extern “C”
#ifdef __cplusplus
}
#endif


如果C++模块要调用C模块,那么C++模块还是需要extern “C”,当然C不用,由于是在头文件的声明中使用,所以使用上面的宏同样能够使得这个头文件也在C中顺利使用。

总结一下就是加上extern “C”在什么情况下都没错,但是要注意函数重载的问题。



def文件是一种比较麻烦的方法,下面是MSDN中的部分内容:
 

模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件。如果不使用 __declspec(dllexport) 关键字导出 DLL 的函数,则 DLL 需要 .def 文件。

.def 文件必须至少包含下列模块定义语句:
1.文件中的第一个语句必须是 LIBRARY 语句。此语句将 .def 文件标识为属于 DLL。LIBRARY 语句的后面是 DLL 的名称。链接器将此名称放到 DLL 的导入库中。
2.EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。通过在函数名的后面加上 @ 符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从 1 到 N,其中 N 是 DLL 导出函数的个数。

例如,包含实现二进制搜索树的代码的 DLL 看上去可能像下面这样:

LIBRARY   BTREE
EXPORTS
   Insert   @1
   Delete   @2
   Member   @3
   Min   @4

 

提示:

如果希望优化 DLL 文件的大小,请对每个导出函数使用 NONAME 属性。使用 NONAME 属性时,序号存储在 DLL 的导出表中而非函数名中。如果导出许多函数,这样做可以节省相当多的空间。


其实__declspec(dllexport)的作用就是让编译器按照某种预定的方式(前面大致解释了这种方式的规则)来输出导出函数及变量的符号,而def文件则是自己为每一个函数和变量指定导出符号,所以def是一个非自动化,手工很强的方式,不是特殊情况的话,实在没有必要浪费这些时间。
还有一个问题,就是使用def会把调用方式和__declspec(dllexport)的作用全部覆盖掉,所以还需要自己处理调用方式不同产生的错误。
一般使用def文件的情况是你需要使用运行时加载,并且需要使用GetProcAddress函数获得函数地址,这个函数需要直接指明函数产生的导出符号,而可以自己指定导出符号的方式就是使用def。
def文件的具体语法可以看看msdn。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436184.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】extern “C“以及__declspec(dllexport) 讲解和def文件dll导出方法

转自:https://blog.csdn.net/qing666888/article/details/41135245 一,__ declspec(dllexport): 将一个函数声名为导出函数,就是说这个函数要被其他程序调用,即作为DLL的一个对外函数接口。通常…

【转】DICOM医学图像处理:浅析SWF、MWL、SPS、MPPS

转自:https://blog.csdn.net/zssureqh/article/details/40151107 背景: 最近重新花时间阅读了DICOM标准,顺带着看了一下HL7标准和IHE,对标题中提到的SWF、MWL、SPS和MPPS有了更进一步的认识,现将自己的理解整理出来&a…

Php点击更换封面,JavaScript_js实现点击图片改变页面背景图的方法,本文实例讲述了js实现点击图 - phpStudy...

js实现点击图片改变页面背景图的方法本文实例讲述了js实现点击图片改变页面背景图的方法。分享给大家供大家参考。具体实现方法如下:点击图片即改变页面的背景图片希望本文所述对大家的javascript程序设计有所帮助。相关阅读:C语言编程中统计输入的行数以及单词个数…

串口通讯基础及S3C2410 UART控制器

数据通信的基本方式可分为并行通信与串行通信两种: 并行通信:是指利用多条数据传输线将一个资料的各位同时传送。它的特点是传输速度快,适用于短距离通信,但要求通讯速率较高的应用场合。 串行通信:是指利用一条传输线…

几个实用的Servlet应用例子-入门、cookie、session及上传文件

1Servlet可以被认为是服务端的applet,它被WEB服务器加载和执行,前端可以显示页面和获得页面数据,后台可以操纵数据库,能完成JavaBean的很多功能。在这里我较为详细的说说Servlet在Cookie,Session和上传文件上的应用&am…

【转】DICOM医学图像处理:DIMSE消息发送与接收“大同小异”之DCMTK fo-dicom mDCM

转自:https://my.oschina.net/zssure/blog/354816 背景: 从DICOM网络传输一文开始,相继介绍了C-ECHO、C-FIND、C-STORE、C-MOVE等DIMSE-C服务的简单实现,博文中的代码给出的实例都是基于fo-dicom库来实现的,原因只有一…

公司间交易学习笔记---概述

本系列笔记是我在学习公司间交易的过程中的随笔,有些是我自己的想法,内容可能跟教程有所出入,由于对AX的应用部分理解得很浅,所以如果错误还请多多指教。 为了处理集团公司中各个分公司之间的交易,AX采用了InterCompan…

用VS2005开发WinCE程序调试图文教程

一、WinCE 模拟器通过ActiveSync 6.1(即Windows Mobile设备中心)连接PC ActiveSync 6.1:http://www.cr173.com/soft/26994.html 1.启动WinCE模拟器 命令行: start .\DeviceEmulator.exe WINCE镜像\Wince5.bin /memsize 256 /video 480x272x16 /sharedf…

【转】 ADO.NET最佳实践

本文转自:http://blog.csdn.net/spidertan/archive/2003/12/13/17110.aspx 概述: 本文在微软站点资源的基础上加工整理而成,意在介绍在你的ADO.NET应用程序中执行和完成性能优化、稳定性和功能性方面提供最佳的解决方案;同…

php 变量文件间传递,同一文件的两个JS函数之间如何传变量?

满意答案ed_ch2013.11.06采纳率:44% 等级:12已帮助:8801人定义成全局变量就可以了var style_key;function change_mystyle(my){style_keymy.options[my.selectedIndex].value;if(style_key 114la){document.getElementById(shoostyleicon…

获取 Web 设计的免费资源

Web 开发人员可以找到很多免费资源,尽管其中一些资源会比另外一些资源更加自由。如果您正在设计网站或 Web 应用程序,那么不管是静态的还是所有可以想到的动态 Ajax 内容,都能找到减轻您的劳动强度并为网站增色的资源。本文从免费图标到 Web …

设计模式C++实现(1)——工厂模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书&#xff0…

java对象间的转型,详细讲述Java中的对象转型

向上转型:子类对象转为父类,父类可以是接口。公式:Father f new Son();Father是父类或接口,son是子类。向下转型:父类对象转为子类。公式:Son s (Son)f;我们将形参设为父类Animal类型,当执行t…

C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)

今天开始这个系列之前,心里有些恐慌,毕竟园子里的高手关于设计模式的经典文章很多很多,特别是大侠李会军、吕震宇 老师的文章更是堪称经典。他们的文笔如行云流水,例子活泼生动,讲解深入浅出。好在他们都是用C#描述&am…

【转】Windows消息传递机制详解

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka Windows是一个消息(Message)驱动系统。Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消…

设计模式C++实现(2)——单例模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书&#xff0…

设计模式C++实现(3)——建造者模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书&#xff0…

宽字符串忽略大小写比较的实现(原)

宽字符串忽略大小写比较的实现(原) 孙文涛 2008-07-24 在Mac机器平台上没有wcsicmp 或 wcscasecmp之类的函数实现对宽字符忽略大小写的比较,所以实现了好几种方法。 一个自然的思路是: (1) wcscpy 原字符串到tmp字符串; (2) tolower tmp字符串; (3) 然后调用仅存的w…

有关JAVA考试中数据库的题,javaee期末考试题库,用javaEE编写一个题库系统,要怎么做...

javaEE数据库简单问题。你插入2113数据库的时候是把5261它封装为一4102个对象插入的吗?1653如果封装为一个User对象版的权话(User对象有ID和LEVEL两个属性)ResultSet rs ps.executeQuery();User user new User();if(rs.hasNext()){user rs.next();}关于javaee 中j…

oracle 12c sql图形化,Oracle 12c PL/SQL程序设计终极指南

Oracle 12c PL/SQL程序设计终极指南作者:孙风栋;王澜;郭晓惠出版日期:2015年06月文件大小:11.73M支持设备:¥60.00在线试读适用客户端:言商书局iPad/iPhone客户端:下载 Android客户端&#xff1a…