簡體   English   中英

將結構體數組作為參數傳遞給函數

[英]Passing an array of structs to a function as a parameter

我知道這個問題已經在stackoverflow中出現了很多時間,當我開始研究這個問題時,我在檢查了stackoverflow提出的所有問題之后發布了這個問題。

基本上,我想實現這一目標。 大圖:將數組結構從c ++ dll傳遞到ac#應用程序。 這里要注意的是,數組的大小只能由c ++ dll確定。 現在我只知道,可以使用out參數作為函數參數來獲取從c ++到c#的任何數組。 是的,我可以將ref作為out參數傳遞給c ++函數,該參數的大小未知,但已初始化為NULL。 但是我不確定這是對的還是行得通! 另一種方法是,將結構體數組作為返回值,對此我在c#中沒有找到任何示例。

所以我做了:將這個問題簡化為一個c ++問題

我嘗試了一些示例示例,以將結構數組從函數返回到main(),從c ++ dll返回到測試c ++應用程序。 ->工作正常。 因此,作為返回值,結構數組可以正常工作。 顯然,由於我不必用確切的大小初始化結構數組,因此從一開始就調用函數來填充數組!

但是要注意的是,我需要以一種可以被c#端接收的可行方式來實現它! 因此,作為函數的out參數,而不作為返回值(如果有人知道如何從c ++ dll到c#接收結構數組,請提供幫助!)。

在stackoverflow或google中,有關將結構數組傳遞給函數的所有問題的大小均已事先確定。 但就我而言,該功能將只能確定大小。 在調用函數之前,我不知道數組的大小。 而且,我實際上是在嘗試通過一個函數調用來完成任務,因此,我不能擁有2個API,一個用於計算大小,一個用於獲取數組。 這將是一個重復的任務,因為相同的功能必須執行兩次,一次只能獲取大小,而另一次則需要獲取實際的數組,這是不可行的!

我有一個示例代碼。 如果有人可以提供幫助,將不勝感激。

// structsEx.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <conio.h>
#include <vector>
#include <string>

using namespace std;
using std::vector;
using std::string;

struct example
{
    char* name; // char* or const char*. But not sure if I can have an
                // std::string.
    int age;
    char* company;
};

void passStructsRef(struct example** ex)  // Again, not sure if I can have 
                                          // std::array or std::vector since 
                                          // this will be the API I expose 
                                          // to C# side.
{
    vector<string> names = {"AAA", "BBB", "CCC", "DDD", "EEE"};
    vector<int> ages = {25, 26, 27, 28, 29, 30};
    vector<string> companies = { "AAA1", "BBB2", "CCC3", "DDD4", "EEE5" };

    *ex = new example[5];  // I think this is a problem. It only initializes 
                           // the first element and hence, I get only the 
                           // first item.
    for (int i = 0; i < 5; i++)
    {
        ex[i] = new example();  // Is this right? Not sure.. 
        ex[i]->age = ages[i];
        ex[i]->name = _strdup(names[i].c_str());
        ex[i]->company = _strdup(companies[i].c_str());
    }

    cout << "2 in function" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << ex[i]->name << "\t" << ex[i]->age << "\t" << ex[i]->company << endl;
    }
}

int main()
{
    example ex;
    ex.age = 30;
    ex.name = "AEIOU";
    ex.company = "ABCDE";

    cout << "1" << endl;
    cout << ex.name << "\t" << ex.age << "\t" << ex.company << endl;

    cout << "2" << endl;
    example *ex2 = nullptr;
    passStructsRef(&ex2);

    for (int i = 0; i < 5; i++)
    {
        cout << ex2[i].name << "\t" << ex2[i].age << "\t" << ex2[i].company << endl;
    }

    _getch();
    return 0;
}

注釋之后,我想我必須對代碼進行一些注釋。 我不確定我是否可以在要向C#應用程序公開的代碼中使用STL數組或向量或std :: string。 這就是為什么我在這里使用new運算符的原因。 下一個可能出現的問題是刪除在哪里? 好吧,我必須有另一個調用delete的API才能刪除為該結構分配的內存。 當我的C#應用​​程序成功接收到我返回的所有數據並對其進行處理后,它將被調用。 那不是問題。 但是將數據發送到C#是一個問題,導致我編寫了此示例C ++測試應用程序。

無需編寫任何大語法或任何特殊代碼即可將數據發送到C#。 如果它在C ++中工作,則必須正確導出參數和API,才能在C#中工作。 這就是為什么我試圖使我的C ++完美。

希望這可以幫助。 非常感謝。

實際上,這里有兩個問題。

一種是如何返回結構數組。

經典的方式是這樣的:

C ++:

int getStructsLength();
int getStructs( int bufferLength, struct example* buffer ); // Returns the count of structures actually written

C#

static extern int getStructsLength();
static extern int getStructs( int bufferLength, [Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] example[] buffer );

另一個是如何在這些結構中返回字符串。

如果沒有太多數據或調用太多,並且無法在Windows上運行,則一種簡單的方法是將const char*更改為BSTR ,並相應地調整C ++代碼。 這些是每種語言都知道如何跨DLL邊界正確分配/取消分配的Unicode字符串。 唯一的缺點是它們相對較慢。

另一種更復雜的方法是在C#結構中聲明以下字段:

 [MarshalAs(UnmanagedType.LPStr)] public string name;

在C ++中,用CoTaskMemAlloc和strcpy調用替換strdup(分配時不要忘記終止“ \\ 0”)。 這樣,互操作器將根據指針生成.NET字符串后釋放這些字符串使用的內存。

最有效的另一種方法是手動編組,即在C#結構中聲明以下字段:

 public IntPtr name;

在C ++中,更改代碼以僅在其中寫入c_str()而不進行復制。

在C#中,使用Marshal.PtrToStringAnsi將它們轉換為.NET字符串。 但是請注意,如果在完成自定義編組之前C ++會更改所有這些字符串,則應用程序將崩潰。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM