2015-03-23 1 views
1

Я пытаюсь понять эту магию «ЭТО РАБОТАЕТ» для взаимодействия C#/C++, но в настоящее время это ТОЛЬКО НОЧНАЯ.Как получить управляемую структуру в C++/native

Я играю с вычислениями Мандельброта и хочу разгрузить вычислительное ядро ​​на родные C++ и SSE2. Это работает с P/Invoke. Теперь я хочу перейти на IJW, быть более типичным и потому, что хочу это понять. Но это были десятилетия назад, когда я поцарапал поверхность C++.

У меня есть struct Complex { double real; double imag; } провести начальные значения для контура Мандельброта, и я хотел бы вызвать функцию так:

Compute(int vectorSize, Complex[] points, double maxValue, int maxLoops, int[] result)

Теперь я создал библиотеку CLR класса с VS Express, 2013 и поместить это в файл заголовка:

public value struct Complex 
{ 
    double real; 
    double imag; 
}; 

public ref class Computations 
{ 
public: 
    static void Basic(int vectorSize, array<Complex,1>^ points, double maxRadius, int maxLoops, array<int,1>^ result); 
}; 

class NativeComputations 
{ 
public: 
    static void Basic(int vectorSize, Complex* points, double maxRadius, int maxLoops, int* result); 
}; 

и в CPP файле это:

#pragma managed 
void Mandelbrot::Computations::Basic(int vectorSize, array<Complex,1>^ points, double maxRadius, int maxLoops, array<int,1>^ result) 
{ 
    pin_ptr<Complex> pPoints = &points[0]; 
    pin_ptr<int> pResult = &result[0]; 
    NativeComputations::Basic(vectorSize, pPoints, maxRadius, maxLoops, pResult); 
} 

#pragma unmanaged 
void Mandelbrot::NativeComputations::Basic(int vectorSize, Complex* points, double maxRadius, int maxLoops, int* result) 
{ 
    double foo = points[0].real; 
} 

На данный момент я застреваю - ошибка C3821: «точки»: управляемый тип или функция не могут использоваться в неуправляемой функции

Поэтому мне нужно использовать что-то неуправляемое. Я могу повторить свой код и объявить структуру ComplexNative (опустив ключевое слово «значение»). Это возможно, но повторите код? И даже если это так, что необходимо для перевода комплекса [] на закрепленный ComplexNative *?

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

ответ

4

Это краеугольный камень управляемого кода. Управляемому компилятору запрещено делать какие-либо предположения о макете типа. Только этот код может быть проверен и безопасен по типу в разных архитектурах. И на самом деле CLR играет с ним трюки, преднамеренно переупорядочивая членов типа, если это создает лучшую компоновку.

Таким образом, управляемая сложная структура не конвертируется в сопоставимый NativeComplex, компилятор просто не может предположить, что эти типы в любом случае идентичны. Что заставляет вас копировать массив, от array<Complex> до NativeComplex[], один элемент и один член за раз.

Ну, это неприятно. Но вы можете обмануть. Это не совсем необоснованно, поэтому в любом случае собственный код не поддается проверке. И ваша декларация структуры имеет особое свойство, это тип blittable. Это дорогое слово, которое означает, что CLR не имеет веской причины фактически выбрать другой макет. Независимо от того, является ли структура на самом деле blittable, это то, что определяется во время выполнения, а также знать маркер-сервер pinvoke. Чья основная задача выполняет то, что вы пытаетесь сделать, вызывая собственный код из управляемой программы и преобразовывая аргументы функции там, где это необходимо.

Но вы не используете марш-сервер pinvoke и маршалинг сложного типа, так как это не встроенная функция C++ Interop (aka IJW). Вы должны будете вызывать сами:

void Mandelbrot::Computations::Basic(int vectorSize, array<Complex,1>^ points, double maxRadius, int maxLoops, array<int,1>^ result) 
{ 
    pin_ptr<Complex> pPoints = &points[0]; 
    NativeComplex* pNative = (NativeComplex*)pPoints; // cheat 
    pin_ptr<int> pResult = &result[0]; 
    NativeComputations::Basic(vectorSize, pNative, maxRadius, maxLoops, pResult); 
} 

который не очень, но вы получите вместе с ним, если вы хотите быстрый код, то вам придется. Имейте в виду, что это никоим образом не является подтверждением слепого литья указателя во всех случаях. Сюрпризы действительно существуют, хорошим примером является this question.

+0

Большое спасибо, Ханс. Я многое узнал из вашего ответа. Но нижняя линия для меня такова: IJW, как P/Invoke, заставляет меня дублировать объявления объектов данных, которые должны быть разделены между native и managed. Мне все еще нужно знать детали структуры структуры на C++ для этого. Если эти заявления становятся сложными или более обширными, необходимо проявлять большую осторожность. Конечно, я признаю, что вам нужно быть осторожным и знать о деталях компоновки структуры, когда вы говорите на C++ :) – Rolf

Смежные вопросы