Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++/CLI->C# error C2526: C linkage function cannot return C++ class

I have a simple .NET dll built with VS2010 C# that exposes 2 static members of a class

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

I then created a Console app from VS2010 C++ and added this function above _tmain

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

Adding the reference and compiling gives me this error

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>          ]

Some of my observations:

  • It compiles successfully if I remove extern "C"
  • It compiles successfully if I rename Test(List<int> test) to Test2(List<int> test)

My question is, what is going wrong and how to fix it from the C++ side.

My current workaround is to rename the method in C#, but I would rather not have to do this, I have a feeling there is a setting I might be missing in my C++ project.

Edit:

I found a better workaround in the C++, it looks like I can wrap the .NET calls in another function.

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

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

It seems silly to have to do this, I'm wondering if it's a compiler bug? What scares me is using such methods and having to worry that the C# developer may at a later point add such a static method and break the C++ builds.

like image 736
PeskyGnat Avatar asked Jun 16 '11 17:06

PeskyGnat


1 Answers

I am just going to take a wild shot here, with the following reasoning:

During compilation MSVC's C++ compiler sees the extern "C" function TestMe() is calling an function Test() inside a class Polygon. Polygon is an incomplete type for the compiler. I guess the compiler cannot see whether the function Polygon::Test(3) is returning an incomplete type or returning anything at all, it decides that it needs to return an error at that point in case the type turns out to not be a plain C-style POD type.

The above seems a reasonable assumption on part of MSVC as in (7.5/9 "Linkage specifications") the C++ standard says:

"Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved."

That would explain the error vanishing once you remove the extern C linkage specification or replace the call to a Cstyle function.

like image 100
Alok Save Avatar answered Oct 03 '22 03:10

Alok Save