2016-08-01 3 views
-1

C++ Так что я передаю массив, который я создал в C# в функцию:Переходя # целочисленный массив C в

options = new int[3]; 
options[0] = 3; 
options[1] = 5; 
options[2] = 4; 
formatvalue(options);// the function header is: formatvalue(object options) 

Отсюда он проходит через несколько интерфейсов и в конечном итоге заканчивается в проекте C++.

В C++ заголовок функции выглядит примерно так: formatvalue(System::Object^ value)

В функции C++, я просто хочу, чтобы прочитать данные. Вся точка передачи в массиве такова, что мне не нужно иметь множество различных аргументов для функции. Это заняло некоторое время, чтобы понять, что передача чего-либо, кроме переменной, дала мне очень странные значения. Сначала я попытался передать ему структуру ints, но бросать System :: Object во что-либо во время компиляции было сложно. И в конце концов я закончил с этим битом C++ кода, вид работ:

int* test; 
memcpy(&test, &value, sizeof(value)); 
int x; 
for (int i = 0; i < 16; i++) 
{ 
    x = *(test + i); 
} 

Что странно, хотя, когда я разыменовать тест, он дает мне некоторые странные мусор, то есть, пока я не получу до * (тест + 4), где начинается мой массив: D. Вот как выглядит память, как:

f8 ае 0b c2 Fe 7f 00 00 03 00 00 00 00 (массив начинается здесь) 00 00 00 03 00 00 00 05 00 00 00 04

Я думал, что тест-адрес указывал на то, что он был первым значением в массиве, вместо этого у меня есть 13 байт мусора, прежде чем мой массив начнется. Кто-то говорил мне, что эти 13 байтов могут быть dope vector? Это будет иметь смысл, так как длина моего массива равна 3, и в первых 13 байтах есть случайное 3 сидения.

Итак вопросы:

  1. Почему адрес теста не начало массива?
  2. Является ли первый 13 байтов вектором допинга?
  3. Правильно ли я использую указатели/memcpy?

Редактировать 1: Изменен первый вопрос.

+0

номер 3 не вопрос вообще –

+0

Seen http://stackoverflow.com/questions/21822882/marshalling-complex-structures-between-c-c? –

+0

@MatiasCicero То же самое для 1. –

ответ

1

Я бы предложил прочитать книгу или некоторые статьи на C++/CLI, так как вы хотите иметь достаточно хорошее представление о том, как ведут себя управляемые и неуправляемые коды и память.

Это не вектор допинга, а данные в начале - это не мусор (ваша программа не могла работать без него!).

Начало массива на самом деле составляет 16 байт, а не 13 байт (см. Выравнивание памяти). Имейте в виду, что память хранится на вашем компьютере малознакомым, поэтому 3 будет храниться как 03 00 00 00, а не 00 00 00 03.

На основе памяти, которую вы предоставили, похоже, что вы инициализируете int* test как адрес массива C#. Дополнительные объекты .NET для отслеживания информации типа информации с помощью указателя таблицы методов. В массивах также есть поле, в котором хранится количество элементов в массиве.В этом случае:

f8 ae 0b c2 fe 7f 00 00 <- Method table pointer (7ffec20baef8) 
03 00 00 00 <- The number of elements in the array 
00 00 00 00 <- Padding 
03 00 00 00 05 00 00 00 04 00 00 00 <- Array data 

Что вы хотите сделать что-то более похожее на это:

array<int>^ arr = /* ... */; 

pin_ptr<int> ptr = &arr[0]; 
int* test = ptr; 

Возьмите адрес первого элемента в массиве. Вы также должны использовать pin_ptr, так как GC может иметь место и перемещать массив в другую область памяти.

В качестве альтернативы вы можете изучить использование P/Invoke вместо C++/CLI. При использовании P/Invoke CLR автоматически обрабатывает пиннинг и гарантирует правильность передачи указателей на массивы и другие типы в собственный метод.

EDIT: Я забыл про вопрос 3.

memcpy принимает указатель источника, указатель назначения, и общее количество байт для копирования (обратите внимание, что это отличается от числа элементов в массиве). Если value является параметром для formatvalue, то sizeof(value) будет таким же, как sizeof(void*). Итак, если указатели источника и адресата были правильными, вы бы только копировали 8 байтов - первые два элемента массива.

Однако указатели на источник и пункт назначения недействительны. Вы определили int* по имени test, но передаете адрес test по адресу memcpy. Вы хотели бы выделить память спереди, присвоить адрес этой памяти test, а затем передать test по значению в memcpy вместо ссылки.

Что-то, как это будет работать:

int* test = allocate_enough_space_for_the_array(); 

array<int>^ arr = dynamic_cast<array<int>^>(value); 

pin_ptr<int> ptr = &arr[0]; 
int* pval = ptr; 

memcpy(test, pval, arr->Length * sizeof(int)); 
+0

Наконец-то он работал, используя ваш метод! Определенно планирование чтения на C++/cli. Спасибо чувак! – Galactasm

+0

Хороший ответ - я очень удивлен, что компилятор не жаловался на '& value' в коде OP (принимать адрес управляемого объекта без' inner_ptr' или 'pin_ptr' не допускается IMO), но я просто проверено, и, к моему удивлению, он компилирует этот по-настоящему сломанный фрагмент кода: - \ –