C++:带有 dllimport/dllexport 的内联函数?
Posted
技术标签:
【中文标题】C++:带有 dllimport/dllexport 的内联函数?【英文标题】:C++ : inline functions with dllimport/dllexport? 【发布时间】:2012-02-11 04:10:31 【问题描述】:我创建了一个 DLL(比如 CORE.DLL),我有如下声明的类/函数:
#ifdef RINZOCORE_SHARED
#define RINZO_LIB __declspec(dllexport)
#else
#define RINZO_LIB __declspec(dllimport)
#endif
我已经用“dllexport”宏定义了很多内联函数,
class RINZO_LIB CVector
public:
CVector();//!< default constructor
..
real& x();//!< accessor for the x component (can be used as l-value too)
real& y();//!< accessor for the y component (can be used as l-value too)
real& z();//!< accessor for the z component (can be used as l-value too)
CVector& operator=(const CVector& other);//!< the assignment
CVector& operator+=(const CVector& other);//!< the sum & assign
CVector& operator-=(const CVector& other);//!< the subtract & assign
CVector& operator*=(const real& fact);//!< the short multiply by a scalar factor & assign
CVector& operator/=(const real& fact);//!< the short divide by a scalar factor & assign
..
RINZO_LIB inline CVector& CVector::operator=(const CVector& other)
//check for 'a=a' case
if (this==&other) return *this;
vec[0]=other.vec[0];
vec[1]=other.vec[1];
vec[2]=other.vec[2];
return *this;
RINZO_LIB inline CVector& CVector::operator+=(const CVector& other)
vec[0]+=other.vec[0];
vec[1]+=other.vec[1];
vec[2]+=other.vec[2];
return *this;
RINZO_LIB inline CVector& CVector::operator-=(const CVector& other)
vec[0]-=other.vec[0];
vec[1]-=other.vec[1];
vec[2]-=other.vec[2];
return *this;
RINZO_LIB inline CVector& CVector::operator*=(const real& fact)
vec[0]*=fact;
vec[1]*=fact;
vec[2]*=fact;
return *this;
RINZO_LIB inline CVector& CVector::operator/=(const real& fact)
assert(fabs(fact) >= epsilon);
vec[0]/=fact;
vec[1]/=fact;
vec[2]/=fact;
return *this;
但是当我使用这个 DLL(导入)编译另一个 DLL(比如 PluginA.DLL)时,它会出现以下编译错误:
Info: resolving std::cout by linking to __imp___ZSt4cout (auto-import)
CMakeFiles\ContourViewer.dir/objects.a(RzStateDoAnimation.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/statemachine/RzStateDoAnimation.cpp:79: undefined reference to `operator!=(quaternion const&, quaternion const&)'
Info: resolving vtable for __cxxabiv1::__vmi_class_type_info by linking to __imp___ZTVN10__cxxabiv121__vmi_class_type_infoE (auto-import)
CMakeFiles\ContourViewer.dir/objects.a(RzStateDoAnimation.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/statemachine/RzStateDoAnimation.cpp:146: undefined reference to `operator==(quaternion const&, quaternion const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:159: undefined reference to `operator*(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:165: undefined reference to `operator^(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:168: undefined reference to `operator-(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator*(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator*(CVector const&, float const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator-(CVector const&, CVector const&)'
关于如何通过 dllexport/dllimport 使用内联函数的任何提示?
【问题讨论】:
你想达到什么目的?显而易见的解决方案有什么问题 - 删除inline
?
@DavidSchwartz 实际上这是代码的一部分,我定义了很多类和很多内联函数。
@AshikaUmangaUmagiliya 如果我错了,请纠正我,但inline
函数不作为单独的代码段存在。事实上,你甚至不能在头文件之外定义它们——它们必须与类声明一起出现并包含在它们所使用的每个编译单元中。因此,对于你的PluginA.cpp
编译,你必须为Core.hpp
提供类声明应该包含所有inline
函数的定义。
将 classes 与 __declspec(dllexport)
一起使用是一个坏主意。由于整个定义都存在于客户端正在使用的头文件中,因此无需导入任何内容。
【参考方案1】:
我想提供一些额外的信息,因为这是一个非常棘手的问题,并且有很多关于导出/导入内联的不正确信息。
首先:内联函数可以毫无问题地与 dllimport/dllexport 一起使用。 意思是完全合理的:您提供一个内联定义,可以在 DLL 内部或客户端代码外部使用(其中可以内联它),但仍然可以像标准导出函数一样访问。换句话说,如果您需要,您仍然可以获得一个指向驻留在 DLL 中 的函数的实现的指针。用例包括,例如,通过 FFI 访问函数,能够访问应该在模块内内联但需要使用 DLL 的 impl 来获取跨越 DLL 边界的内存的内存分配/释放例程等。
请参阅https://devblogs.microsoft.com/oldnewthing/20140109-00/?p=2123 以获得全面的处理和澄清同时内联和导出/导入的含义。
接下来,在您的具体情况下,我认为您正在尝试做的事情没有任何问题。您想为自己和客户提供快速的内联矢量数学,同时仍然能够像标准导出一样访问该函数。如果最后一点不正确(即,您不'永远不需要一个指向函数的 DLL 实现的指针),那么 cmets/answer 是正确的:删除导出/导入并使其成为 .hpp 的一部分。 仅当您知道仍需要访问 DLL 的导出版本的函数时才使用 import/export + inline。同样,这是一件非常合理的事情,但是,通常并不是必需的——所以请确保你确实需要它。
话虽如此,您的 DLL 似乎没有导出符号。
仔细检查以确保您在构建库时定义了RINZOCORE_SHARED
。检查 DLL 的符号并查看这些函数是否已导出(如果没有,并且您确定您已经定义了 RINZOCORE_SHARED
,那么我真的很难过)。
检查以确保您在调用它的任何地方都包含具有函数定义的标头。检查以确保您的插件构建中未定义 RINZOCORE_SHARED
。看起来您的插件正在尝试查找函数的导出版本,这似乎暗示它没有这些内联函数的定义。
我通常只将它与 C 链接函数一起使用,所以老实说,我不太确定 C++ ABI 可能出了什么问题。
【讨论】:
它应该确实有效。我现在有一个奇怪的现象,如果构造函数是 DLL 导出并声明 noexcept 内联提示被拒绝。没有 noexcept 就可以了。【参考方案2】:注意:由于这是已接受的答案,因此无法删除。请考虑将其从逻辑上删除。欢迎您投反对票。
原始内容保留在下面以供历史参考。
内联和 dllexport/dllimport 不能混用。
你也可以
-
内联您的函数,并为使用它们的每个源文件分别编译它们;或
将它们存储在库中,即只编译一次(导出它们),然后将程序的其余部分与该单个编译版本链接(导入它们)。
同时做这两件事没有什么意义。
从具有两者的每个函数定义中删除inline
或RINZO_LIB
,你应该没问题。
编辑为了消除任何误解:可以导出和导入内联函数,实际上只需在声明中放置 dllexport/dllimport 即可。
【讨论】:
他们做到了,他所做的事情没有理由不能做。在他的特殊情况下,其他原因导致了问题。请参阅blogs.msdn.microsoft.com/oldnewthing/20140109-00/?p=2123,了解有关导出和导入内联的详细讨论。 @JoshParnell 我没有说这是不可能的,我说这没有意义。我不关心实际导出/导入内联函数的方式,直到有令人信服的理由使用此功能,我只是在这里(或其他地方)看不到。因此,一个实用的建议是:不要那样做。 没关系,我只是想让下一个想知道他们如何将可内联向量数学导出到静态代码和脚本接口的人知道完整的故事,而不是看到你回复的第一句话并认为它不是可以导出内联符号。你是对的,这可能不是这个特定的海报需要做的。 Raymond Chens "The Old New Thing" 博客文章中关于 "Can you dllexport/dllimport an inline function" 的链接已移动:devblogs.microsoft.com/oldnewthing/20140109-00/?p=2123以上是关于C++:带有 dllimport/dllexport 的内联函数?的主要内容,如果未能解决你的问题,请参考以下文章