在DLL编程中,导出函数为什么需要extern "C"
2016-03-10 19:58
435 查看
一般来讲,在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
问:要说在不同编程语言之间共享dll文件的导出函数的话,在函数前加 WINAPI 就够了,为什么要加 extern "C"
防止C++编译器的“名字破坏”特性
extern "C"的作用是,使编译器按照c的方式生成函数名,c的方式实际的函数名和你写的一样。如果没有这个,则按照c++的方式生成函数名,这样实际的函数名(LoadLibrary方式GetProcAddress传入的函数名)和你写得函数名不一样,这样你用LoadLibrary、GetProcAddress这种方式调用dll就不成功。
但是用引入库的方式调用,则编译器自动转换函数名,所以总是没有问题。
http://www.qqgb.com/program/vc/vcjq/program_166495.html
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
问:要说在不同编程语言之间共享dll文件的导出函数的话,在函数前加 WINAPI 就够了,为什么要加 extern "C"
防止C++编译器的“名字破坏”特性
extern "C"的作用是,使编译器按照c的方式生成函数名,c的方式实际的函数名和你写的一样。如果没有这个,则按照c++的方式生成函数名,这样实际的函数名(LoadLibrary方式GetProcAddress传入的函数名)和你写得函数名不一样,这样你用LoadLibrary、GetProcAddress这种方式调用dll就不成功。
但是用引入库的方式调用,则编译器自动转换函数名,所以总是没有问题。
http://www.qqgb.com/program/vc/vcjq/program_166495.html
相关文章推荐
- Java小白手记2:一些名词解释
- Java编程思想学习(九) 异常处理
- Java小白手记2:一些名词解释
- 枚举
- C++面试(题)
- C++ map 的两种插入数据方法
- c/c++之:main函数参数
- 浅谈 C++ 中的 new/delete 和 new[]/delete[]
- C语言访问mysql数据库
- codeforces 651B B. Beautiful Paintings(贪心JAVA代码)
- [Java开发之路](19)Long缓存问题
- C和C++混合编程(__cplusplus使用)
- Java继承_接口练习题
- uiatuomator提示shortMsg=java.lang.RuntimeException
- 认识JAVA
- 初学django
- 虎小五进阶之路 · JDK的安装和环境配置
- C#日期格式化,时间
- Spring IOC XML Annotation
- leetcode leetcode 209 : Minimum Size Subarray Sum | Java最短代码实现