在MinGW中导入内联函数

问题描述 投票:4回答:2

我正在使用一个共享库,在其标题中定义内联函数。

这是一个简化的测试用例,如链接到库的编译单元所见(对于库所见的版本,只需用dllimport替换dllexport)。

class __declspec(dllimport) MyClass {
public:
    int myFunc2();
    int myFunc1();
};

inline int MyClass::myFunc2(void) {
    return myFunc1();
}

inline int MyClass::myFunc1(void) {
    return 0;
}

编译它会发出警告:

警告:'int MyClass :: myFunc1()'在用dll链接引用后重新声明没有dllimport属性[默认启用]

请注意,定义函数的顺序很重要,因为在myFunc1的定义之前放置myFunc2的定义不会导致警告。

另请注意,此代码在Visual C ++下编译时没有警告。这些警告至少对MinGW来说是特定的,也许对GCC来说是一般的。编辑:我想到我可能必须验证警告是否未被项目设置的标志之一禁止。

我的问题是:

  • 为什么会这样?
  • 在类声明中将myFunc1声明为inline可以解决问题。这是为什么 ?它也反对recommended way做事。
  • 还有另一种(更好的?)方法来解决这个问题吗?
c++ dll linker mingw inline
2个回答
5
投票

问题的出现是因为dllimport的工作方式有些神奇,通常意味着你只需要在第一次声明时使用它。

基本上,当你将一个函数声明为dllimport然后在除了dllimport之外用相同的声明重新声明该函数时,第二个声明隐式地获得dllimport。如果重新声明不相同,则不会获得隐式dllimport。

那么这里发生的是你首先将函数声明为dllimport / non-inline,然后将其声明为非dllimport / inline。在第一个声明中添加内联可以解决问题,因为第二个声明会隐式变为dllimport。或者,在第二个声明中添加__declspec(dllimport)应该可以解决问题。

请注意,重新排序定义会消除警告,因为警告是在重新声明之前使用它。通过重新排序,您在重新声明之前不再使用它,因此您不会收到任何警告,尽管它将使用非dllimport版本(即,它永远不会使用dll中的函数版本)。

另请注意,使用内联dllimport是危险的。任何针对dll构建的程序都可能在某些地方使用内联函数,而在其他地方使用非内联函数(来自dll)。即使这两个函数现在完全相同,dll的未来版本也可能会发生变化并具有不同的实现。如果使用新版本的dll运行,那么旧程序可能会开始行为不端。


0
投票

有关Chris Dodd答案的更多信息:

我测试了MSVC 2017和MinGW-w64 7.2.0;在这两种情况下,启用优化后,myFunc1()myFunc2调用解析为内联版本,尽管有警告。即使myFunc1的身体被移动到main()以下。

所以我的初步结论是忽略这个警告是安全的。


为了清理编译,MinGW-W64中唯一可行的方法是将类定义中的函数声明标记为inline。编译器不允许将__declspec(dllimport)应用于类外函数定义。

我一直无法确定g ++是否有警告标志,它将专门禁用此警告。

© www.soinside.com 2019 - 2024. All rights reserved.