如何正确编组从Unity到C / C ++的字符串?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何正确编组从Unity到C / C ++的字符串?相关的知识,希望对你有一定的参考价值。
以下代码片段来自Unities Bonjour客户端示例,该示例演示了如何与C#中的本机代码进行交互。这是一个简单的C函数,它将字符串返回给C#(Unity):
char* MakeStringCopy (const char* string)
{
if (string == NULL)
return NULL;
char* res = (char*)malloc(strlen(string) + 1);
strcpy(res, string);
return res;
}
const char* _GetLookupStatus ()
{
// By default mono string marshaler creates .Net string for returned UTF-8 C string
// and calls free for returned value, thus returned strings should be allocated on heap
return MakeStringCopy([[delegateObject getStatus] UTF8String]);
}
该函数的C#声明如下:
[DllImport ("__Internal")]
private static extern string _GetLookupStatus ();
这里有一些令我困惑的事情:
- 这是将字符串从ios本机代码返回到C#的正确方法吗?
- 如何释放返回的字符串?
- 有没有更好的方法呢?
任何有关此事的见解都表示赞赏。谢谢。
1.no.
你必须自己做。
。是的
如果在C或C ++端的函数内部分配内存,则必须释放它。我没有看到任何代码分配内存,但我认为你离开了那一部分。另外,不要将堆栈上声明的变量返回给C#。最终会出现未定义的行为,包括崩溃。
Here是一个C ++解决方案。
对于C解决方案:
char* getByteArray()
{
//Create your array(Allocate memory)
char * arrayTest = malloc( 2 * sizeof(char) );
//Do something to the Array
arrayTest[0]=3;
arrayTest[1]=5;
//Return it
return arrayTest;
}
int freeMem(char* arrayPtr){
free(arrayPtr);
return 0;
}
唯一的区别是C版本使用malloc
和free
函数来分配和取消分配内存。
C#:
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr getByteArray();
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
public static extern int freeMem(IntPtr ptr);
//Test
void Start()
{
//Call and return the pointer
IntPtr returnedPtr = getIntArray();
//Create new Variable to Store the result
byte[] returnedResult = new byte[2];
//Copy from result pointer to the C# variable
Marshal.Copy(returnedPtr, returnedResult, 0, 2);
//Free native memory
freeMem(returnedPtr);
//The returned value is saved in the returnedResult variable
byte val1 = returnedResult[0];
byte val2 = returnedResult[1];
}
请注意,这只是一个使用仅包含2个字符的char的测试。您可以通过向C#函数添加out int outValue
参数然后将int* outValue
参数添加到C函数来使字符串的大小动态化。然后,您可以在C侧写入此参数的字符大小,并从C#侧访问该大小。
然后可以将此大小传递给Marshal.Copy
函数的最后一个参数,并删除当前硬编码的2值限制。我会留下这个让你做,但如果困惑,请参阅this帖子,例如。
更好的解决方案是将StringBuilder
传递给本机端然后写入它。不好的一面是你必须按时申报StringBuilder
的大小。
C ++:
void __cdecl _GetLookupStatus (char* data, size_t size)
{
strcpy_s(data, size, "Test");
}
C#:
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
public static extern int _GetLookupStatus(StringBuilder data, int size);
//Test
void Start()
{
StringBuilder buffer = new StringBuilder(500);
_GetLookupStatus (buffer, buffer.Capacity);
string result = buffer.ToString();
}
如果您正在寻找最快的方法,那么您应该在C#端使用char数组,将其固定在C#端,然后将其作为IntPtr
发送给C.在C端,您可以使用strcpy_s
来修改char数组。这样,在C端没有分配内存。您只是从C#重用char数组的内存。您可以在答案float[]
的末尾看到here示例。
以上是关于如何正确编组从Unity到C / C ++的字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C 代码正确创建 DLL 并在 C++ 项目中使用它
如何使用 pinvoke 将二进制数据缓冲区从 C 传递到 C#