Use C++ type without copying

Dear all,

Being a newbie I don't know if this is a recurrent topic... please forgive the question if this is the case.

I have a Xamarin.Forms test application that I'd like to link with a C++ library. So far, I've created an interface in the Forms project, and in iOS I've written an implementation class that calls the native library. It works, but now I need to pass significant data between the two.

How can I pass and retrieve data from the C++ library without copying it?

Reading online I've seen here that I can copy data to/from plain old data, like arrays, but I'd like to do this without any duplication.

Moreover, is it possible to use C++ types like std::vector or std::map?

Thanks!

Tagged:

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    You're going to be very limited in what you can access from C# without copying. You can do structs (if you use attributes to control the layout of the struct in C#) and arrays, but anything that isn't a POD type in C++ should be considered off limits. A detailed description of what that means can be found here. Trying to do this with STL data structures is not a good idea. Instead you should either define your data structures in C++ to be friendly to use outside of C++ or you should provide a C++ API for dealing with the data within C++.

  • FrancoMilicchioFrancoMilicchio ITMember ✭✭

    Thanks Adam, can you clarify how I can have a C#/struct pairing with attributes? I am really a newbie here...

    Thank you!

  • adamkempadamkemp USInsider, Developer Group Leader mod

    See here.

  • FrancoMilicchioFrancoMilicchio ITMember ✭✭

    Thanks @adamkemp, I was able to compile something! However, it seems that I don't understand the layout with two different functions. I tried to use a pointer and return a class. The class, as suggested by your link, is packed and standard layout:

    //===== H FILE =====
    #pragma pack(push, 1)
    class stuff
    {
    public:
        char c;
        int  i;
    };
    #pragma pack(pop)
    
    extern "C" int doStuff();
    
    extern "C" void usePtr(stuff *p);
    
    extern "C" stuff returnStuff();
    
    //===== CPP FILE =====
    int doStuff()
    {
        std::string s("abcd");
    
        return s.length();
    }
    
    void usePtr(stuff *p)
    {
        p->c = 'X';
        p->i = 23;
    }
    
    stuff returnStuff()
    {
        stuff t;
    
        t.c = 'A';
        t.i = 42;
    
        return t;
    }
    

    And in the C# source I have

            public int nativeDoStuff()
            {
                cppclass q;
    
                q.nativec = '-';
                q.nativei = 111;
    
                usePtr (ref q);
    
                var p = returnStuff ();
    
                return doStuff ();
            }
    
            [DllImport("__Internal")]
            public extern static int doStuff();
    
            [DllImport("__Internal")]
            public extern static void usePtr(ref cppclass p);
    
            [DllImport("__Internal")]
            public extern static cppclass returnStuff();
    

    When I step into nativeDoStuff(), when using the pointer the q.nativec gets 'X' correctly, but the integer is zero. When using the returnStuff call, I just get almost random stuff: it is almost always 32 for nativec and 8 for nativei, but the character sometimes vary.

    What am I doing wrong?

    Thanks!

  • FrancoMilicchioFrancoMilicchio ITMember ✭✭

    I forgot the C# class definition, sorry!

        [StructLayout(LayoutKind.Sequential)]
        public struct cppclass {
            public char nativec;
            public int  nativei;
        }
    
  • adamkempadamkemp USInsider, Developer Group Leader mod

    The problem is probably that char in C# is not the same as char in C. A char in C is just a single byte by definition. The equivalent in C# is just called byte

    However, I don't know where you are getting the suggestion to use #pragma pack. That's not something I would recommend. Instead you should learn how the C type is natively laid out and then use the structure layout attributes in C# to tell the compiler how to match that layout. Using #pragma pack will hurt performance on most CPUs, and some architectures strictly disallow misaligned reads or writes, which means you could crash (I don't know whether ARM is one of those architectures).

Sign In or Register to comment.