【转】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,一经查实,立即删除!

相关文章

JAGUARSDN1网络的开机自动启动 禁用,WIFI模块的启动关闭控制

先确认下系统中有没有加载NDISPWR.DLL,如果没有的话,把这个组件加上 WIFI在默认情况下,是开机自动打开的,如果要开机禁用,在HKEY_LOCAL_MACHINE/Comm/NdisPower创建一个键值 name 4 name是你用的WIFI的名字 如果想…

高考临考突发情况应急预案大全

临考感冒看卷头痛如何应对 高考应急预案助考生 明天,全省49万余考生就将走进高考考场,考生顺利迎考是全社会的心愿,可种种意外总有可能出现在考生面前。高考过程中遇到意外情况如何处理?昨天,本报记者约请了多位考试专…

php病毒图片后缀名,脚本图片类后门病毒的完美使用方法

前两天,看了一篇《脚本注入图片新方法》的文章,相信很多人都通过这篇文章了解了如何在图片中加入脚本,以及如何在正常的asp(或php)文件中通过include函数使图片中的脚本产生效用。但是,这种方法的问题又随之而来了:有人…

WPF指南之XAML概述

[转]WPF指南之XAML概述 周日, 05/04/2008 - 23:26 — robot 出处: it168要赢得世界,必须在恰当的时间做出恰当的事。这一点,微软做到了。历经微软DOS,Win 31, Win95, Win 98, Win 2k, WinXP, 一路走来,一次比一次热闹,…

如何修改wince的网络配置

如何修改wince的网络配置呢? 首先,必须知道网卡驱动名字。在s3c2410上,名字叫“CS8900”,用工具连接上wince查看他的注册表。你将可以得到下面的东西。 [HKEY_LOCAL_MACHINE/Comm/CS8900] "DisplayName""CS8900&qu…

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

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

php源码查找替换,php 替换模板中的 PHP源码标签字符方法

//替换php代码function RepPhpAspJspcode($string){global $public_r;if(!$public_r[candocode]){//$stringstr_replace("<?xml ","[!--ecms.xml--]",$string);$stringstr_replace("$stringstr_replace("\\>","\\>",$s…

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

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

Parallel Extensions CTP第二版发布

Parallel Extensions CTP第二版发布 LazyBee 2008年6月微软Parallel Extensions项目组发布了Parallel Extendsions CTP的第二个版本。这个版本主要包含以下组件&#xff1a; 1 任务并行库TPL(Task Parallel Library): 提供命令的方式将面向数据的操作以及轻量级的任务自动的运行…

wince中的背光灯控制

要控制背光灯就必须知道相关设置&#xff0c;以下是wince中背光灯的设置。在BL_ReadRegistry函数中被读取。 [HKEY_CURRENT_USER/ControlPanel/BackLight] "ACTimeout"dword:0000012c "UseExt"dword:00000001 "UseBattery"dword:00000001 …

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

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

VistaDB 数据库,.NET的新选择

VistaDB 3.3 fully managed embedded database engine runs Nothing but .Net! Designed and built as a 100% managed code database engine. Now with TSQL Procs! 商业版&#xff0c;提供ADO.NET 2.0 的Provider。商业版。但是有 Express 版&#xff0c;可应用于非商业环境。…

wince中重启网卡

WCHAR Name[]_T("CS89001/0"); HANDLE m_hFileHandle CreateFile(_T("NDS0:"), 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) INVALID_HANDLE_VALUE); if( m_hFileHandle INVALID_HANDLE_VALUE ) { //获得网卡名时打开设备错误 …

【转】DICOM的常用Tag分类和说明

转自&#xff1a;https://blog.csdn.net/inter_peng/article/details/46513847 1. 前言&#xff1a; 基于DICOM3.0标准的医学图像中&#xff0c;每一张图像中都携带着许多的信息&#xff0c;这些信息主要可以分为Patient, Study, Series和Image四类。每一个DICOM Tag都…

matlab电压稳定极限,电力系统电压稳定性的Matlab建模分析

Matlab软件作为一个编程效率高、程序设计灵活、图形功能强的工程实用的分析软件,在电力系统的仿真分析及相关计算中得以广泛应用,特别是其中的Simulink工具箱可以实现电力系统的模型建立及动态仿真[1].但是在实际应用中,特别是针对电力系统的动态过程分析,Simulink存在以下2个问…

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

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

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

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

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

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

php记录登录时间,php记录 用户当前页面停留时间

onunload JS定时器 ajax 实现每秒写一次数据库肯定是不行的资源释放都来不及&#xff0c;使用js计时器&#xff0c;在离开页面时&#xff0c;调用ajax异步插入数据库&#xff0c;即不延迟跳转&#xff0c;也不会占用资源&#xff0c;插入完就释放了HTML onunload 事件属性定义…

WinCE驱动开发问题精华集锦

如何让系统加载自己写的驱动程序&#xff1f;两种办法&#xff1a; 1、在[HKEY_LOCAL_MACHINE/Drivers/BuiltIn]下添加注册键。 2、在应用程序中调用ActivateDeviceEx。 在一些文件中用分号来表示注释&#xff0c;例如下面的内容 ; CESYSGEN IF SERVERS_MODULES_HTTPD …