C ++ DLL def文件中的重载函数
我正在编写一个C / C ++ DLL,并希望导出在使用像这样的.def文件之前完成的某些功能。
LIBRARY "MyLib" EXPORTS Foo Bar
使用这样定义的代码,例如:
int Foo(int a); void Bar(int foo);
但是,如果我想像下面这样声明Foo()的重载方法,该怎么办:
int Foo(int a, int b);
由于def文件仅具有函数名称,而没有完整的原型,因此我看不到它将如何处理重载的函数。我们是否只使用一个条目,然后在将正确原型的函数指针传递给LoadLibrary()时指定所需的重载版本?
编辑:要清楚,这是在Windows上使用Visual Studio 2005
编辑:将非def(__declspec)方法标记为答案...我知道这实际上并不能解决我想要的使用def文件的问题,但是似乎没有使用def文件的(官方)解决方案。但是,如果有人知道我们没有重载的函数和def文件,这将使问题悬而未决。
解决方案
回答
在代码本身中,使用__declspec(dllexport)标记要导出的函数。例如:
#define DllExport __declspec(dllexport) int DllExport Foo( int a ) { // implementation } int DllExport Foo( int a, int b ) { // implementation }
如果这样做,则无需在.def文件中列出功能。
或者,我们可以使用默认参数值,例如:
int Foo( int a, int b = -1 )
假定存在一个b值,我们可以使用该值指示未使用。如果-1是b的合法值,或者没有或者不应该使用默认值,则此方法将无效。
编辑(Adam Haile):已更正以使用__declspec作为__dllspec是不正确的,因此我可以将其标记为正式答案...它足够接近。
编辑(Graeme):糟糕,感谢我们纠正我的错字!
回答
函数重载是一种C ++功能,它依赖于名称处理(链接器错误消息中的隐秘功能名称)。
通过将变形的名称写入def文件,我可以使测试项目链接并运行:
LIBRARY "TestDLL" EXPORTS ?Foo@@YAXH@Z ?Foo@@YAXHH@Z
似乎为
void Foo( int x ); void Foo( int x, int y );
因此,从错误消息中复制C ++函数名称,并将它们写入def文件中。但是,真正的问题是:为什么要使用def文件而不使用__declspec(dllexport)?
我使用VC ++ 2008进行了测试,这些杂乱的名称是不可移植的。
回答
没有语言或者版本不可知的方法来导出重载函数,因为随着每个编译器版本的发布,更改约定都会改变。
这就是为什么大多数WinXX函数具有有趣的名称(如* Ex或者* 2)的原因之一。
回答
没有正式的方法可以执行我们想要的操作,因为dll接口是C api。
编译器本身使用整改的名称作为解决方法,因此,当我们不想在代码中进行太多更改时,应使用整改的名称。
回答
我有一个类似的问题,所以我也想发布。
- 通常使用
extern "C" __declspec(dllexport) void Foo();
导出函数名称就可以了。通常它将导出不需要修改的名称,而无需.def文件。但是,也有一些例外,例如__stdcall函数和重载的函数名。
- 如果我们声明一个函数使用__stdcall约定(就像许多API函数一样),那么
extern "C" __declspec(dllexport) void __stdcall Foo();
将导出一个错误的名称,例如_Foo @ 4. 在这种情况下,我们可能需要将导出的名称显式映射到内部错误的名称。
A.如何导出一个完整的名称。在.def文件中添加
---- EXPORTS ; Explicit exports can go here Foo -----
这将尝试为内部函数Foo找到"最佳匹配"并将其导出。在上述情况下,只有
一个foo这将创建映射
Foo = _Foo @ 4
如通过dumpbin / EXPORTS可以看到的
如果我们重载了一个函数名,则可能需要在.def文件中明确说明我们想要的函数
通过使用entryname [= internalname]语法指定错误的名称。例如
---- EXPORTS ; Explicit exports can go here Foo=_Foo@4 -----
B..def文件的替代方法是我们可以使用#pragma"就地"导出名称。
#pragma comment(linker, "/export:Foo=_Foo@4")
C.第三种选择是仅声明Foo的一个版本作为外部" C",以不加破坏地导出。有关详细信息,请参见此处。