如何正确编组从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 (); 

这里有一些令我困惑的事情:

  1. 这是将字符串从iOS本机代码返回到C#的正确方法吗?
  2. 如何释放返回的字符串?
  3. 有没有更好的方法呢?

任何有关此事的见解都表示赞赏。 谢谢。

1,没有。

2,你必须自己做。

3。是的

如果在C或C ++端的函数内部分配内存,则必须释放它。 我没有看到任何代码分配内存,但我假设你离开了那一部分。 另外,不要将堆栈上声明的变量返回给C#。 最终会出现未定义的行为,包括崩溃。

这是一个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){ delete[] arrayPtr; free(arrayPtr); return 0; } 

唯一的区别是C版本使用mallocfree函数来分配和取消分配内存。

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#,并从C#侧访问该大小。

然后可以将此大小传递给Marshal.Copy函数的最后一个参数,并删除当前硬编码的2值限制。 我会留下这个给你做,但如果感到困惑,请参阅这篇文章,例如。


更好的解决方案是将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[]示例。

Interesting Posts