首页 / C# / c# – 从C本机插件更新float数组
c# – 从C本机插件更新float数组
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 从C本机插件更新float数组,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4070字,纯文字阅读大概需要6分钟。
内容图文
![c# – 从C本机插件更新float数组](/upload/InfoBanner/zyjiaocheng/710/fd3ed4bfabad4abd8a8ebb67552d147e.jpg)
在尝试将数组从C传递到C#时,我看到了一个非常奇怪的问题.我正在使用Marshal.Copy(具体来说:https://msdn.microsoft.com/en-us/library/a53bd6cz(v=vs.110).aspx).
问题:从C到C#的浮点数组在结果数组中产生一些NaN.
(注意:我在Unity游戏引擎的上下文中工作)
码
示例C代码:
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API getSomeFloats(float** points, int* count) {
std::vector<float> results;
std::vector<SOME_TYPE> key_points = <SOME_POINTS>
for (auto iter = key_points.begin(); iter < key_points.end(); iter++) {
results.push_back(static_cast<float>(iter->pt.x));
results.push_back(static_cast<float>(iter->pt.y));
}
*points = results.data();
*count = results.size();
//<Print results to csv here>
return true;
}
示例C#代码:
[DllImport("NativePlugin")]
private static extern bool getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
private static float[] getFloatArrayFromNative() {
IntPtr ptrResultItems = IntPtr.Zero;
int resultItemsLength = 0;
bool success = getSomeFloats (ref ptrResultItems, ref resultItemsLength);
float[] resultItems = null;
if (success) {
// Load the results into a managed array.
resultItems = new float[resultItemsLength];
Marshal.Copy (ptrResultItems
, resultItems
, 0
, resultItemsLength);
// <PRINT out resultItems to csv here>
return resultItems;
} else {
Debug.Log ("Something went wrong getting some floats");
return new float[] { -1, -2 };
}
}
示例输出:
请看以下示例:
C输出(print_out.csv):
123, 456, 789
C#输出(print_out_cs.csv):
123, NaN, 789
我完全被这个困扰了.我只是不明白为什么只有一些(大约7/100)花车返回NaN.有没有人有任何可能有帮助的建议/见解?
谢谢!
解决方法:
在您的代码中发现几个问题:
1. std :: vector< float>结果;在堆栈上声明.它会在函数返回时消失.将其声明为指针
std::vector<float> *results = new std::vector<float>(10);
但请务必声明一个将在C端释放它的函数.
2.功能参数不匹配.
你的C:
getSomeFloats(float** points, int* count, CameraPose* pose)
你的C#:
getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
您必须从C侧删除CameraPose * pose或将IntPtr姿势添加到C#侧.
3.使用UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API.
你不需要那个.当您想使用Unity的内置函数(如GL.IssuePluginEvent)时使用此选项.在这种情况下,您不使用它.
这应该这样做:
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
}
}
4.C#有一个垃圾收集器,可以在内存中移动变量.如果要从C端修改C#数组,则必须将其固定.你只需要固定C#数组.另一种选择是在C端分配数组,将其返回C#将其复制到C#端的临时变量,然后在C端删除它.
5.将结果复制回数组而不是分配它.
推荐方法:
有很多方法可以做到这一点,其中一些非常慢.如果你想使用Marshal.Copy,你必须在C端分配数组,否则你将遇到一些未定义的行为.
最快和最有效的方法是将C#端的数组分配为全局变量.将数组及其长度传递给本机端.还传递第三个参数,C可用于告诉C#已更新或写入的索引量.
这比创建新数组要好得多,将其复制到C#变量,然后在每次调用函数时将其销毁.
这是你应该使用的:
C :
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
std::vector<float> results;
for (int i = 0; i < count; i++)
{
//Fill the array
data[i] = results[i];
}
*outValue = results.size();
}
}
您还可以使用:std :: copy(data,data count,results.begin());而不是循环来复制数据.
C#:
[DllImport("NativePlugin", CallingConvention = CallingConvention.Cdecl)]
private static extern void fillArrayNative(IntPtr data, int count, out int outValue);
public unsafe void getFillArrayNative(float[] outArray, int count, out int outValue)
{
//Pin Memory
fixed (float* p = outArray)
{
fillArrayNative((IntPtr)p, count, out outValue);
}
}
用法:
const int arraySize = 44500;
float[] arrayToFill = new float[arraySize];
void Start()
{
int length = arrayToFill.Length;
int filledAmount = 0;
getFillArrayNative(arrayToFill, length, out filledAmount);
//You can then loop through it with with the returned filledAmount
for (int i = 0; i < filledAmount; i++)
{
//Do something with arrayToFill[i]
}
}
这只是一个例子,它比我之前使用过的所有其他方法都快.避免按照Marshal.Copy目前的方式进行操作.如果您仍然希望按照自己的方式进行操作或使用Marshal.Copy,那么here是执行此操作的合适方法,需要在每次调用中分配,复制数据和取消分配内存.
内容总结
以上是互联网集市为您收集整理的c# – 从C本机插件更新float数组全部内容,希望文章能够帮你解决c# – 从C本机插件更新float数组所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。