一、在Unity中使用c++代碼
Unity想調用C++代碼,則需要c++開發人員打包成so庫。
在Unity中通過DllImport,和dll一樣調用。
需要注意的點:
C++代碼需要extern"C"來封裝成dll
因為unity默認使用c語言調用外部接口,會對c++代碼進行命名矯正,使用extern"C"避免這個問題。
so在Unity中的存放路徑為Plugins/Android/Libs/arm64-v8a
二、參數傳遞
1.結構體需對照數據類型創建。
2.參數個數和格式要一一對應,int16使用short,int32使用long, int8使用byte。
3.結構體數組,在向so傳遞時,使用IntPtr
三、調用用例,添加回調
回調方法需要添加聲明[UnmanagedFunctionPointer(CallingConvention.cdecl)]
[DlLImport(dlName:"soTest",CallingConvention = CallingConvention.Cdect)]publi static extern bool soMethod(string str, string num, Callback callBack);
[UnmanagedFunctionPointer(CallingConvention.cdecl)]
public delegate void Callback(string msg);
四、傳遞結構體數組情況
1. 結構體定義與內存對齊??
??C++端??:
cpp
#pragma pack(push, 1) // 強制1字節對齊,避免編譯器填充字節[1,9](@ref)
struct MyStruct {int id;float value;char name[32]; // 固定長度字符數組
};
#pragma pack(pop)// 導出函數聲明(確保符號可見)
extern "C" __attribute__((visibility("default")))
void ProcessStructArray(MyStruct* arr, int size);
??C#端??:
csharp
[StructLayout(LayoutKind.Sequential, Pack = 1)] // 與C++內存布局一致[1,9](@ref)
public struct MyStruct {public int id;public float value;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 固定長度字符串映射[4,11](@ref)public string name;
}
2.C#端分配非托管內存并傳遞??
csharp
[DllImport("MyLib", CallingConvention = CallingConvention.Cdecl)]
public static extern void ProcessStructArray(IntPtr structArray, int size);void SendData() {MyStruct[] data = new MyStruct[3];// 填充數據...// 分配非托管內存int structSize = Marshal.SizeOf(typeof(MyStruct));IntPtr buffer = Marshal.AllocHGlobal(structSize * data.Length);// 逐個復制結構體到內存[1,5](@ref)for (int i = 0; i < data.Length; i++) {IntPtr ptr = new IntPtr(buffer.ToInt64() + i * structSize);Marshal.StructureToPtr(data[i], ptr, false);}// 調用C++函數ProcessStructArray(buffer, data.Length);// 釋放內存(必須手動釋放)Marshal.FreeHGlobal(buffer);
}
3. C++端接收并處理數據??
??
cpp
void ProcessStructArray(MyStruct* arr, int size) {for (int i = 0; i < size; i++) {MyStruct& s = arr[i];// 修改數據(如數值運算)s.value *= 2.0f;printf("ID: %d, Name: %s\n", s.id, s.name);}
}
4.??關鍵注意事項??
??內存對齊問題??
C#必須使用[StructLayout(LayoutKind.Sequential, Pack = 1)],
C++需用#pragma pack強制對齊,確保雙方結構體大小和字段偏移一致。
驗證工具:通過Marshal.OffsetOf(typeof(MyStruct), “field”)檢查偏移量。
??字符串處理??
C#字符串需用[MarshalAs(UnmanagedType.ByValTStr)]映射為固定長度字符數組,避免C++端緩沖區溢出。
??函數導出與平臺差異??
Linux/Mac的.so庫需以lib前綴命名(如libMyLib.so),C#的DllImport需省略前綴。
使用nm -D libMyLib.so檢查導出符號是否存在。
??內存管理??
??必須顯式釋放??:Marshal.AllocHGlobal分配的內存需調用FreeHGlobal,否則導致內存泄漏。
避免野指針:傳遞完成后C++不應保留對內存的引用。