gpt4 book ai didi

c# - 如何将托管结构放入 C++/ native

转载 作者:太空宇宙 更新时间:2023-11-03 21:23:11 25 4
gpt4 key购买 nike

我正在尝试理解 C#/C++ 互操作的这种“它只是工作”的魔力,但目前它只是一场噩梦。

我正在玩 Mandelbrot 计算,想将计算核心卸载到原生 C++ 和 SSE2。这与 P/Invoke 一起工作。现在我想改用 IJW,以提高类型安全性,因为我想了解它。但那是几十年前,当我触及 C++ 的皮毛时。

我有一个 struct Complex { double real;双像; } 来保存 Mandelbrot 循环的起始值,我想调用这样的函数:

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

现在我使用 VS Express 2013 创建了一个 CLR 类库并将其放入头文件中:

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 结构(通过省略“value”关键字)。这是可行的,但重复代码?即使是这样,将 Complex[] 转换为固定的 ComplexNative* 有什么必要?

拜托,我不想将结构拆分为 double[] real,double[] imag。这可能会导致更简单的解决方法,但我想知道如何正确地做到这一点。

最佳答案

这是托管代码的基石,禁止托管编译器对类型布局做出任何假设。只有这样,代码才能在不同的体系结构中实现可验证和类型安全。事实上,CLR 会在其中耍花招,故意对类型的成员重新排序,如果这样可以产生更好的布局。

因此托管 Complex 结构无法转换为可比较的 NativeComplex,编译器根本无法假定这些类型在任何方面都是相同的。这迫使您从 array<Complex>复制数组到 NativeComplex[] ,一次一个元素和一个成员。

嗯,这很不愉快。但是你可以作弊。这样做并非完全不合理,无论如何 native 代码都不可验证。而且你的结构声明有一个特殊的属性,它是一个blittable类型。这是一个昂贵的词,意味着 CLR 没有充分的理由实际选择不同的布局。一个结构是否实际上是 blittable 也是在运行时确定的,pinvoke 编码器需要知道。他们的主要工作是做您正在尝试做的事情,从托管程序调用 native 代码并在必要时转换函数参数。

但是您没有使用 pinvoke 编码器,像这样的复杂类型编码不是 C++ Interop(又名 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 .

关于c# - 如何将托管结构放入 C++/ native ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29219839/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com