- Home /
IL2CPP C# passed ref float[] to C++ can't get right result
Hi, i was trying to write a C++ .a lib for iOS IL2CPP , and try to pass a ref float[] to a C++ func. In C++ proj, i init the float[]'s element, and want to get the value in C# code, but in C# script i get the float[] length is 1,not what i passed to C++.
eg:
C# Script :
[DllImport ("__Internal")]
private static extern bool TestRef(ref float[] array);
void Start()
{
Debug.LogError ("Before TestRef");
float[] a = new float[5];
for(int i = 0; i < a.Length; i++)
i = -1;
TestRef (ref a);
Debug.LogError ("After TestRef : " + a.Length);
for (int i = 0; i < a.Length; i++)
Debug.LogError ("a[" + i + "] = " + a[i]);
}
C++ Plugin:
bool TestRef(float*& a)
{
cout << "[Plugin] Begin" << endl;
for (Int i = 0; i < 5; i++)
{
a[i] = i;
}
cout << "[Plugin] After" << endl;
return true;
}
and after run this demo, i get
After TestRef : 1
a[0] = 0
after google i got this :
The il2cpp_codegen_marshal_array function simply returns a pointer to the existing managed array memory, that’s it!
http://blogs.unity3d.com/cn/2015/07/02/il2cpp-internals-pinvoke-wrappers/
and i want to know how to get the right result: a = {0,1,2,3,4}
and btw this code run everything ok at Mac, PC, iOS(not IL2CPP) so i believe it is something about IL2CPP
thanks all ~
Hi Mr. Wang, did you get any solution on this issue, I got the very same error in 2021
Answer by JoshPeterson · Jul 12, 2016 at 11:34 AM
To accomplish what the native code does in this case, you don't really need to pass the array by reference.
You could instead make the C# code look like this:
[DllImport ("__Internal")]
private static extern bool TestRef(float[] array);
// Existing C# code to create the array an call the native code here.
Then the native code would look like this:
bool TestRef(float[5] a)
{
cout << "[Plugin] Begin" << endl;
for (Int i = 0; i < 5; i++)
{
a[i] = i;
}
cout << "[Plugin] After" << endl;
return true;
}
It is really only beneficial to pass an array from managed to native code by reference if you want to allocate new memory for the array in native code. That is certainly possible, but I would avoid it if you don't need it, as it does add some complexity.
If you do need to pass the array to native code by reference, you'll want to tell the runtime (IL2CPP, in this case) the size of the array using the SizeParamIndex marshaling directive. It looks like this:
[DllImport ("__Internal")]
private static extern bool TestRef([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] float[] array, int size);
// Existing C# code to create the array an call the native code here.
This marshaling directive means that the argument at index 1 (`size` in this case) is an integer that indicates the size of the managed array. The runtime uses this information to determine how to properly marshal the array to native code.
Then your native code should look something like this:
bool TestRef(float** a, int size)
{
cout << "[Plugin] Begin" << endl;
for (Int i = 0; i < size; i++)
{
a[i] = i;
}
cout << "[Plugin] After" << endl;
return true;
}