11

我有一个用 VS2010 C# 构建的简单 .NET dll,它公开了一个类的 2 个静态成员

public class Polygon
{
    public static void Test(int test) {}
    public static void Test(List<int> test) {}
}

然后我从 VS2010 C++ 创建了一个控制台应用程序,并在 _tmain 上方添加了这个函数

extern "C" void TestMe()
{
    Polygon::Test(3);
}

添加引用和编译给了我这个错误

1>WierdError.cpp(9): error C2526: 'System::Collections::Generic::List<T>::GetEnumerator' : C linkage function cannot return C++ class 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see declaration of 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see reference to class generic instantiation 'System::Collections::Generic::List<T>' being compiled
1>          with
1>          [
1>              T=int
1>          ]

我的一些观察:

  • 如果我删除 extern "C",它将成功编译
  • 如果我重命名Test(List<int> test)为,它将成功编译Test2(List<int> test)

我的问题是,出了什么问题以及如何从 C++ 端修复它。

我目前的解决方法是重命名 C# 中的方法,但我宁愿不必这样做,我觉得我的 C++ 项目中可能缺少一个设置。

编辑:

我在 C++ 中找到了更好的解决方法,看起来我可以将 .NET 调用包装在另一个函数中。

void wrapper()
{
    Polygon::Test(3);
}

extern "C" void TestMe()
{
    wrapper();
}

必须这样做似乎很愚蠢,我想知道这是否是编译器错误?让我害怕的是使用这样的方法并且不得不担心 C# 开发人员可能会在以后添加这样的静态方法并破坏 C++ 构建。

4

1 回答 1

6

我将在这里进行一次疯狂的拍摄,理由如下:

在编译期间,MSVC 的 C++ 编译器看到extern "C" function TestMe()正在调用Test()类中的函数PolygonPolygon是编译器的不完整类型。我猜编译器无法看到该函数Polygon::Test(3)是返回一个不完整的类型还是返回任何东西,它决定此时需要返回一个错误,以防该类型不是纯 C 风格的 POD 类型。

以上似乎是对部分 MSVC 的合理假设,如 C++ 标准(7.5/9“链接规范”)中所说:

“从 C++ 到其他语言定义的对象以及从其他语言到 C++ 定义的对象的链接是实现定义和语言相关的。只有在两种语言实现的对象布局策略足够相似的情况下,才能实现这种链接。”

这将解释一旦您删除extern C链接规范或替换对 Cstyle 函数的调用,错误就会消失。

于 2011-06-16T17:50:56.563 回答