Можно ли упорядочить указатель в массив при передаче структуры?

В приведенном ниже примере dataArray, определенный в C++, работает, если он определен как массив, но не как указатель (просто выводит мусорные данные). Есть ли другой способ маршалировать массив C#, чтобы он считывал указатель как массив?

C#

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CSharpFoo{
    int alpha;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5]
    public int[] dataArray;
    int beta;
}

C++

struct CPPFoo{
    int alpha;
    //int* dataArray; //Doesn't work, even though initialized to an array elsewhere
    int dataArray[5];
    int beta;
}

Проходит через функцию вроде этой
C#

[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public extern static bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)] ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(CSharpFoo value);

C++

//Callback
typedef void(__stdcall * ResultCallback)(CPPFoo);
__declspec(dllexport) bool InitializeDLL(ResultCallback callback);

Заранее спасибо!

Редактировать:: Потому что "инициализирован массивом в другом месте" неясно:

CPPFoo(int dummy){ //Constructor
    alpha = 32;
    dataArray = new int[5];
    for (int i = 0; i < 5; i++){
        dataArray[i] = i;
    }
    beta = 13;
}
//dataArray C++ {0,1,2,3,4}
//alpha C# 32
//dataArray C# {Total random garbage} (dataArray[3] is 13!)
//beta C# 0

PS, структура CPPFoo - это сложная структура, полученная из библиотеки DLL, поэтому я не могу ее изменить. На данный момент, чтобы все заработало, я копирую его в более подходящий массив, как в ответе NonCreature0714, но это приводит к тому, что все данные копируются - дважды. Я стараюсь избегать этой двойной копии.

Другое редактирование: Хотя кажется, что для структуры, содержащей один массив, значения передаются правильно, для сложной структуры выбрасывается мусор. Я обновил код, чтобы отразить более сложную структуру!

Пожалуйста, определите «не работает».

PaulMcKenzie 25.12.2018 06:08

Мусорные данные. Сейчас буду редактировать

Mars 25.12.2018 06:09
int* dataArray; - Для нас это мусор. Мы не знаем, на что указывает этот указатель, поскольку он неинициализирован. Возможно, то, что вы думали, это локальная переменная (поэтому больше не существует).
PaulMcKenzie 25.12.2018 06:10

Инициализирован массивом в другом месте? Я получаю его из отдельной DLL, и в документации он упоминается как указатель на массив.

Mars 25.12.2018 06:13

Я считаю, что он все равно не удастся, даже если вы объявите его 'int * dataArray = new int [5]'

Mars 25.12.2018 06:15
int* dataArray = new int[5]. Это динамически создает массив неинициализированный из 5 целых чисел. Итак, как узнать, работает ли это, если вы ничего не устанавливаете для элементов?
PaulMcKenzie 25.12.2018 06:17

Извините, привел пример. Я точно знаю, что DLL возвращает действительные данные и что данные в полном порядке до момента перехода от C++ к C#.

Mars 25.12.2018 06:18

@ EmrahSüngü Извините, я использую DllImport, его просто не было в фиктивном коде. Я добавлю это сейчас

Mars 25.12.2018 07:18

Почему бы просто не использовать vector<int> dataArray; и передать ссылку на вектор?

NonCreature0714 25.12.2018 07:24

@ NonCreature0714, потому что это не просто 1 массив, это сложная структура, содержащая данные, полученные из DLL (поэтому я не могу ее изменить)

Mars 25.12.2018 07:38

@Mars, ох, понял, это было мне непонятно. Это важная деталь, не могли бы вы отредактировать свой ответ, чтобы указать это?

NonCreature0714 25.12.2018 07:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
95
3

Ответы 3

Мой опыт работы с C# очень ограничен, но кажется, что он работает с int dataArray [5];, потому что код соответствует типу CSharpFoo и CPPFoo. Размер обоих - пять ints. Когда вы меняете тип на указатель, тогда размер одного указателя составляет пять целых чисел, а другого - одного указателя, который будет меньше пяти целых чисел.

Скорее всего, для передачи массива динамического размера потребуется размер, и для получения указателя вам может потребоваться что-то сделать с небезопасным кодом, но я не пишу на C#, так что это всего лишь предположение.

struct CPPFoo {
    int* dataArray = nullptr;
    int size = 0;
}

Спасибо. Передача его как массива фиксированного размера не является невозможной, но это означает двойное копирование данных, что далеко не идеально.

Mars 25.12.2018 06:53

Я думал, что вы можете передать адрес исходного массива, поэтому я думал о небезопасном блоке C#. Можно ли присвоить адрес и размер массива. Затем код C++ может передать его в тип vector <int>. Я немного догадываюсь, если честно. Я думаю, что копия нужна только для права собственности. Если копирование не производится, должна быть какая-то гарантия, что массив целых чисел останется до тех пор, пока код C++ не перестанет ссылаться на него.

Erik Wesemann 25.12.2018 07:11

Вариант для рассмотрения, но в настоящее время unsafe не включен, и я не знаю, разрешит ли это клиент

Mars 25.12.2018 07:15

что-то вроде int [] = new int [size];

Erik Wesemann 25.12.2018 07:30

Извините, я нажал Enter на последнем комментарии, прежде чем был готов. Я думаю, что [MarshalAs (UnmanagedType.ByValArray, SizeConst = 5] может быть тем, что нужно изменить. Может ли что-то вроде следующего работать на C#? Что происходит без маршала ...? Public struct CSharpFoo {public int [] dataArray; public int dataSize;}

Erik Wesemann 25.12.2018 07:38

Извините за путаницу, я пытался помочь, но я думаю, что усугубил ситуацию. Я новичок в этой публикации.

Erik Wesemann 25.12.2018 07:40

Код будет легче понять, если вы вместо этого «отредактируете» свой ответ :)

Mars 25.12.2018 07:41

Но для справки, без маршала приложение вылетает!

Mars 25.12.2018 07:54

Используйте вектор.

#include <vector>

struct CPPFoo {
    std::vector<int> dataArray;
};

Вектор более читабелен и безопасен. Только хилый увеличивает размер кода и лишь немного медленнее, чем использование примитивного массива. Вам также не нужно беспокоиться о том, чтобы поддерживать переменную для размера и обновлять ее каждый раз, когда она изменяется.

Я провел пару тестов на своей локальной машине, насколько я понял ваш код. У меня не было проблем со следующим кодом

C# сторона

struct Foo
{
    public int alpha;

    public IntPtr Data;

    public int beta;

    public void GetData(ref int[] buffer,int length)
    {
        Marshal.Copy(Data,buffer,0,length);
    }

}

программа класса {

    [DllImport("MyPtr.dll",EntryPoint = "InitializeDLL", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)]ResultCallback callbackPointer);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void ResultCallback(ref Foo value);

    static void CallBackMe(ref Foo value)
    {
        var buffer = new int[5];
        value.GetData(ref buffer,buffer.Length);
    }
    static void Main(string[] args)
    {
        InitializeDLL(CallBackMe);
    }
}

Сторона C++

struct CPPFoo {
    int* dataArrayPtr;
    CPPFoo()
    {
        dataArrayPtr = new int[5];
        for (int i = 0; i < 5; i++) {
            dataArrayPtr[i] = i;
        }
    }
};

typedef void(__stdcall * ResultCallback)(CPPFoo);
extern "C" __declspec(dllexport) bool InitializeDLL(ResultCallback callback)
{
    CPPFoo f;
    callback(f);
    return true;
}

Код в действии

Это интересно! Но это не сработало. Подожди, пока я обновляю вопрос

Mars 25.12.2018 11:48

@Mars, подскажите, пожалуйста, что именно не сработало? У меня этот код работает без проблем

Hasan Emrah Süngü 25.12.2018 11:50

Я обновил код. Пожалуйста, попробуйте еще раз с более сложной структурой :)

Mars 25.12.2018 11:54

@Mars, да, массив стал мусорным значением

Hasan Emrah Süngü 25.12.2018 11:59

@Mars, привет я обновил свой ответ рабочей копией

Hasan Emrah Süngü 25.12.2018 12:49

Хм ... есть ли причина, по которой Foo стал эталоном?

Mars 25.12.2018 13:24

@Mars, может быть, вы правы, может быть, небольшая разница. Я поспешно проверил, прежде чем покинуть офис. Но снимок экрана - это последний код, и он работает. Нет никакой конкретной причины, по которой я сделал это ссылкой. Личные предпочтения, при пинвокинге передаю как ref. С реф работает или без него

Hasan Emrah Süngü 25.12.2018 13:27

Я думаю, что использование IntPtr позволит мне, по крайней мере, избежать копирования вещей один раз на стороне C++, а затем еще раз при переходе с C++ на C#, но на данный момент все работает грубо, поэтому проект двинулся дальше. Я тоже скоро ухожу из офиса, так что проверю позже!

Mars 25.12.2018 13:28

@Mars,then お疲れ様です

Hasan Emrah Süngü 25.12.2018 13:30

お疲れ様です!To you to!

Mars 25.12.2018 13:31

Кстати, ты до чертиков напугал меня, когда я говорю по-японски, ха-ха

Mars 25.12.2018 14:05

@ Марс, я просто нажал на ваш профиль, надеясь получить некоторую информацию о том, где вы живете, потому что вы сказали, что покидаете офис, когда я уходил ? Оказывается, мы оба в Японии

Hasan Emrah Süngü 25.12.2018 14:23

Другие вопросы по теме