Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# P/Invoke访问的Pin数据_C#_C++_Clr_Pinvoke - Fatal编程技术网

C# P/Invoke访问的Pin数据

C# P/Invoke访问的Pin数据,c#,c++,clr,pinvoke,C#,C++,Clr,Pinvoke,我使用p/Invoke将数据从C++代码传递到C++代码,反之亦然。到目前为止,这一切都很好 最近我读了一些文章(例如),需要对这些数据进行钉扎,因为GC在C++执行任务时可能会重新排列或删除它们。 我查阅了一些微软的文章,但对我来说,它们并不完全清楚何时需要手动进行钉扎。我对本文的理解是,CLR确保在GC收集数据时不会出现任何问题。它通过将数据固定或复制到GC不收集的非托管内存中来实现。所以对我来说,这意味着程序员不需要考虑钉住。本文中的示例也没有显示任何固定。我仍然不确定我的结论是否正确 进

我使用p/Invoke将数据从C++代码传递到C++代码,反之亦然。到目前为止,这一切都很好

<>最近我读了一些文章(例如),需要对这些数据进行钉扎,因为GC在C++执行任务时可能会重新排列或删除它们。 我查阅了一些微软的文章,但对我来说,它们并不完全清楚何时需要手动进行钉扎。我对本文的理解是,CLR确保在GC收集数据时不会出现任何问题。它通过将数据固定或复制到GC不收集的非托管内存中来实现。所以对我来说,这意味着程序员不需要考虑钉住。本文中的示例也没有显示任何固定。我仍然不确定我的结论是否正确

进一步挖掘,我发现了我在代码中使用的特定数据类型的更多信息:

int
long
:按值传递-因此不能固定。但是
ref int

IntPtr
:我使用AllocHGlobal()在非托管内存中分配空间。总司令没有触及这一点。所以不需要钉住

byte[]
:通过引用传递,但自动固定。请参阅:作为一种优化,在封送处理期间,将固定只包含可blittable成员的可blittable类型和类的数组,而不是复制这些数组

string
:通过引用传递,但自动固定。请参阅:在封送处理对象(如字符串)时,会自动执行固定,但是您也可以使用GCHandle类手动固定内存

string[]
“带字符串的自定义结构”
:这里我真的不确定。“在封送处理字符串[…]等对象时自动执行固定”这句话是否包括字符串数组和自定义结构

目前,我没有任何pin码,代码工作正常。甚至当我强制GC收集的同时C++正在执行它的任务。当然,这并不意味着它总是可以正常工作。 我使用.NETFramework4.8


我是否需要对所提到的数据类型进行固定?

此处的规则取决于您调用的内容,因此,在没有具体示例的情况下,只能给出模糊的建议,但是:

如果您通过p/Invoke调用的方法仅在p/Invoke调用期间使用指针,那么:在几乎所有情况下,您都可以传递一个隐式指针,或者在调用周围使用
fixed
(即,如果p/Invoke签名仅声明
SomeStruct*
IntPtr
)将正常工作

如果您通过p/Invoke调用的方法在指针返回之前存储了指针,然后期望该指针有意义(可能对于基于回调的异步/完成API),那么在这种情况下,您需要确保数据不会移动:

  • 对于非托管内存,例如来自
    AllocHGlobal
    :无需任何操作
  • 对于堆栈下部的内存(即堆栈帧在此期间不会被重用的位置):无需任何操作
    • (如果您将堆栈内存用于P/Invoke,但无法满足该条件:您犯了严重的设计错误)
  • 对于托管内存(堆上的对象等);这就是乐趣的开始;请注意,.NET5引入了“固定对象堆”(通常用于P/Invoke的数组),但除此之外:您需要手动固定对象堆

Argh,博客帖子。它没有很好地描述在什么样的场景下你需要这样做。这是非常罕见的,一个需要它的api在非托管代码中使用起来和pinvoke一样困难和危险。仅当非托管代码存储您传递的指针时,才需要显式固定。您可能需要一个初始化函数、一个或多个实用程序函数来转换或提取您传递的数据中的信息,以及(希望)一个释放函数来表示您不再对实用程序函数进行任何调用。感谢您的快速响应。因此,如果我只在函数调用期间使用传递的指针,那么我不需要固定它们?这是正确的。