更快地以数组形式返回数据的c++接口

本文关键字:数据 返回 c++ 接口 数组 | 更新日期: 2023-09-27 18:18:33

这是一个非常干净的解决方案,可以从非托管的c++代码中marsahall一个struct数组。当涉及到简单性时,它是最完美的解决方案,我花了一段时间来理解这个概念,所以在几行代码中,正如你可以看到的c# Main(),我有一个填充的结构数组准备"收获"..

typedef struct {
int Id;
BSTR StrVal;
}Package;
extern "C" __declspec(dllexport) void dodata(int requestedLength,int StringSize, Package **Packs){
    int count;
    count=0;
    *Packs = (Package*)LocalAlloc(0, requestedLength * sizeof(Package));
    Package *Cur = *Packs;
    while(count!= requestedLength)
    {
        Cur[count].StrVal = NULL;
        Cur[count].Id = count;
        Cur[count].StrVal=SysAllocString(L"abcdefghij");
        Cur[count].StrVal[StringSize-1]=count+'0';
    ++count;
    }
}
c#

[DllImport(@"ExportStructArr.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void dodata(int requestedLength, int StringSize, out IntPtr csPkPtr);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct csPk
{
    public int V;
    [MarshalAsAttribute(UnmanagedType.BStr, SizeConst = 10)]
    public string testStr;
}
static void Main(string[] args){
    int ArrL = 16000;
    csPk[] Cpk = new csPk[ArrL];
    IntPtr CpkPtr = IntPtr.Zero;
    int szPk = Marshal.SizeOf(typeof(csPk));
    dodata(ArrL, 10, out CpkPtr);
}

现在我要做的就是:

        for (int i = 0; i < Cpk.Length; i++)
        {
            Cpk[i] = (csPk)Marshal.PtrToStructure(new IntPtr(CpkPtr.ToInt32() + (szPk * i)), typeof(csPk));
        }
如您所见,解决方案非常简单问题是使用不安全的或任何类型的数据转换,甚至到字节…

我如何优化它以更好地返回数据?

编辑:

链接,我试图从这里的其他答案学习:

  • 汉斯·帕桑特的回答
  • AbdElRaheim的回答
  • supercat的回答

也试过Google: wikipedia, github post by stephentoub

更快地以数组形式返回数据的c++接口

这是一个完整的快速的解决方案来填充对象列表,我已经尽力了我很乐意提出意见和建议。

c++

typedef struct _DataPacket
{
    BSTR buffer;
    UINT size;
} DataPacket;
extern "C" __declspec(dllexport)  void GetPacksUnsafe( int size, DataPacket** DpArray )
{
    int szr = size;int count=0;
    *DpArray = (DataPacket*)CoTaskMemAlloc( szr * sizeof( DataPacket ));
    if ( DpArray != NULL )
    {
        DataPacket* CurPack = *DpArray;
        for ( int i = 0; i < szr; i++, CurPack++ )
        {
            CurPack->size = i;
            CurPack->buffer = SysAllocString(L"SomeText00");
            CurPack->buffer[9]=i+'0';   
        }
    }
}
c#

    [DllImport(@"ExportStructArr.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
    public static extern void GetPacksUnsafe(int size, PackU** outPackUArr);
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PackU
    {
        public char* StrVal;
        public int IntVal;
    }

    public static unsafe List<PackU> PopulateLstPackU(int ArrL)
    {
        PackU* PackUArrOut;
        List<PackU> RtLstPackU = new List<PackU>(ArrL);
        GetPacksUnsafe(ArrL, &PackUArrOut);
        PackU* CurrentPack = PackUArrOut;
        for (int i = 0; i < ArrL; i++, CurrentPack++)
        {
            RtLstPackU.Add(new PackU(){ StrVal = CurrentPack->StrVal, IntVal=CurrentPack->IntVal});
        }
        Marshal.FreeCoTaskMem((IntPtr)PackUArrOut);
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("{0}", new string(RtLstPackU[i].StrVal));
        }
        return RtLstPackU;
    }

使用代码是尽可能简单的

    static unsafe void Main(string[] args)
    {
        int ArrL = 100000;
        List<PackU> LstPackU;
        LstPackU = PopulateLstPackU(ArrL);
    }

在那里你有一个自定义数据列表,快如子弹子弹…

编辑

使用指针代替字符串:

typedef struct _DataPackCharPnt
{
    char* buffer;
    UINT IntVal;
} DataPackCharPnt;

extern "C" __declspec(dllexport)  void GetPacksPnt( int size, DataPackCharPnt** DpArrPnt )
{
    int count = 0;
    int TmpStrSize = 10;
    *DpArrPnt = (DataPackCharPnt*)CoTaskMemAlloc( size * sizeof( DataPackCharPnt ));
    DataPackCharPnt* CurPackPnt = *DpArrPnt;
    char dummyStringDataObject[]= "abcdefgHi";
    for ( int i = 0; i < size; i++,CurPackPnt++ )
    {
        dummyStringDataObject[9] = i+'0';
        CurPackPnt->IntVal=i;
        CurPackPnt->buffer = (char*)malloc(sizeof(char)*TmpStrSize);
        strcpy(CurPackPnt->buffer, dummyStringDataObject);
    }
}

将填充100k个元素所需的时间从11 ms减少到7 ms

在创建buffer时是否有可以省略的部分?

  • dummyStringDataObject的职责是模拟工作,说得到一个文件名,然后用它的值设置缓冲区,所以除了这个额外的时间,这是这个函数的全部目的,返回一些未知的值和字符串的长度…