转自:http://blog.csdn.net/zhongjling/article/details/8088664

一般来讲,在DLL编程过程中,对于导出的函数前 都需要加入 extern “C”,

extern 表示这是个全局函数,可以供各个其他的函数调用;

“C” 表示编译时按照 C编译器的方式进行编译,而不是C++。 C++的编译方式考虑了函数重载,所以对函数名进行了新的修饰,产生了所谓的破坏性命名。

不过,也有特殊情况,有三种例外情况可以不加extern   “C”: 
1、如果不是用C++编译器而是用C编译DLL,名字不会变,可以不加extern   "C" 
2、如果DLL的使用者知道是用C++编译器编译DLL,不加extern   “C”也可以,因为他知道名字改变的规则。调用GetProcAddress时,把函数名字改了就是了,改为修饰后的函数名。 如 fnDll1  改为 ?fnDll1@@YAHXZ。

例子关键代码如下: 
---------------------------- 
DLL部分: 
//   This   is   an   example   of   an   exported   function. 
DLL1_API   int   __cdecl   fnDll1(void) 

return   42; 

输出的修饰函数名为?fnDll1@@YAHXZ 

DLL1_API   int   __cdecl   fnDll1(int   a) 

return   42+a; 

输出的修饰函数名为?fnDll1@@YAHH@Z 
----------------------------- 
EXE部分: 
HINSTANCE   hModule   =   LoadLibrary("dll1.dll"); 
ASSERT(hModule); 
typedef   int   (*fnDll1)(); 
fnDll1   pfnDll1   =   NULL; 
//VERIFY(pfnDll1   =   (fnDll1)::GetProcAddress(hModule,   "fnDll1")); 
VERIFY(pfnDll1   =   (fnDll1)::GetProcAddress(hModule,   "?fnDll1@@YAHXZ")); 
ASSERT(pfnDll1()   ==   42); 

typedef   int   (*fnDll2)(int); 
fnDll2   pfnDll2   =   NULL; 
VERIFY(pfnDll2   =   (fnDll2)::GetProcAddress(hModule,   "?fnDll1@@YAHH@Z")); 
ASSERT(pfnDll2(3)   ==   45); 
--------------------------- 

3.上面的2太麻烦了。所以还有一种方法是使用def文件。

 (如果DLL使用的是def文件,要删除TestDll.h文件中关键字extern "C",即2者是不能共存的)。

def 文件(模板定义文件),第一个语句必须是 LIBRARY 语句,指出DLL的名字;

EXPORTS语句 列出被导出函数的名字;将要输出的函数罗列出来,这个函数名字必须与定义函数的名字完全一致,如此既可以得到

一个没有任何修饰符的函数名了。

被导出的函数 可以和一个序号相对应。定义序号时必须在数字前加一个@。例如  isRUINIan  @1      //IsRuiNian 函数对应序号为 1

这样的话,我们既可以GetProAddress(hinstance,“IsRuiNian”),也可以 GetProAddress(hinstance,(LPCSTR)1)实现调用。

  

参考:http://topic.csdn.net/t/20021012/17/1090973.html

http://www.qqgb.com/program/vc/vcjq/program_166495.html

在DLL编程中,导出函数为什么需要extern "C"的更多相关文章

  1. DLL中导出函数的两种方式(dllexport与.def文件)

    DLL中导出函数的声明有两种方式: 一种方式是:在函数声明中加上__declspec(dllexport): 另外一种方式是:采用模块定义(.def)文件声明,(.def)文件为链接器提供了有关被链接 ...

  2. (转)DLL中导出函数的两种方式(dllexport与.def文件)

    DLL中导出函数的两种方式(dllexport与.def文件)http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792 ...

  3. 【转】DLL中导出函数的两种方式(dllexport与.def文件)

    DLL中导出函数的两种方式(dllexport与.def文件) DLL中导出函数的声明有两种方式: 一种方式是:在函数声明中加上__declspec(dllexport):另外一种方式是:采用模块定义 ...

  4. VC 使用msxml6.dll动态链接库中的函数读写XML文件

    VC 使用msxml6.dll动态链接库中的函数读写XML文件 目录 1 引言 2 .dll使用方法 3 常用函数总结 4 实例应用 5 运行效果预览 6 补充说明 7 不足之处 8 更新   引言: ...

  5. 理解函数式编程中的函数组合--Monoids(二)

    使用函数式语言来建立领域模型--类型组合 理解函数式编程语言中的组合--前言(一) 理解函数式编程中的函数组合--Monoids(二) 继上篇文章引出<范畴论>之后,我准备通过几篇文章,来 ...

  6. Windows编程中回调函数的使用心得(MFC篇)

    回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定 ...

  7. C++ DLL中导出函数的声明的方法

    定义: TESTDLLEXPORT_API int fnTestDllExport(void); TESTDLLEXPORT_API int fnTestCall(void); TESTDLLEXPO ...

  8. MFC DLL中导出函数模板

    //my.h struct AFX_EXT_CLASS B { }; struct AFX_EXT_CLASS C { }; class AFX_EXT_CLASS A { public: templ ...

  9. 【转】 嵌入式C语言编程中Inline函数的应用

    源地址:https://blog.csdn.net/vigour1000/article/details/9622037 有一段儿时间没写写经验笔记了,哎,也是自己这一段时间以来(其实最近一直是这个状 ...

随机推荐

  1. Android弹出一项权限请求

    Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(ena ...

  2. 打开cmd闪退

    我们在使用电脑过程中一般会很少用到cmd命令,CMD命令窗口在一些特殊情况时我们会用到,如PING下看网络通不通.在CMD窗口里运行命令如磁盘格式转换,但是有些朋友遇到了这样的问题,在开始运行输入CM ...

  3. 《C++ Primer Plus》第6章 学习笔记

    使用引导程序选择不同操作的语句后,程序和编程将更有趣.C++提供了if 语句 .if else 语 句 和 switch 语句来管理选项.if 语句使程序有条件地执行语句或语句块,也就是说,如果满足特 ...

  4. java基础---->string字面量的使用

    这里简单的理解一下java中关于string字面量的知识,关于字节码可以使用java自带的javap工具查看. string字面量 一.直接贴出测试的代码 A string literal alway ...

  5. android EditText自动弹出和自动关闭软键盘

    程序进入某个activity直接弹出软键盘,不能直接在OnCreate中设置,必须等View绘制事件完毕才可以弹出,需要用到Timer辅助实现,如果要实现输入的功能,必须让EditText获得焦点. ...

  6. Map中存放数组

    Map<String,Object> map = new HashMap<String, Object>(); Map<String,String> agentMa ...

  7. highcharts配置的效果如下

    配置如下: function init(categoryArray,seriesData,month_first_day,month_last_day,currDay){ var chart = Hi ...

  8. Java Swing 日历 控件

    这是我改写的网上的DateChooser代码后的作品,使用效果如图所示.用法参考备注,以及Main函数中用法. /** * * Copyright: Ares. * All Rights Reserv ...

  9. Oracle涂抹oracle学习笔记第9章RMAN说,我能恢复

    RMAN中的恢复对应两个操作:数据库修复(restore)和数据库恢复(recover) 数据库修复(restore):是指利用备份集的数据文件来替换已经损坏的数据库文件或者将其恢复到一个新的位置.R ...

  10. 通过Nginx反向代理实现IP分流

    通过Nginx做反向代理来实现分流,以减轻服务器的负载和压力是比较常见的一种服务器部署架构.本文将分享一个如何根据来路IP来进行分流的方法. 根据特定IP来实现分流 将IP地址的最后一段最后一位为0或 ...