Unity在类型定义时,使用class会导致Unity闪退
//注意这里不能使用class,只能使用struct
[StructLayout(LayoutKind.Sequential)]
public struct Touch
{
public int id;
public float x, y;
public float time;
}
Unity调用:
[DllImport(DllName)]
private static extern Touch testTouch(Touch touch);
C++ dll类型定义
//这里可以使用class,C++的class与struct没太大区别
class Touch
{
public:
int id;
float x, y;
int state;
double time;
Touch(int _id, float _x, float _y, int _type, double _time)
:id(_id), x(_x), y(_y), state(_type), time(_time)
{
}
Touch()
:id(0), x(0), y(0), state(0), time(0)
{
}
};
C++ 函数定义:
__declspec(dllexport) Touch testTouch(Touch touch)
{
//测试,Unity的类实例作为函数参数,进行处理
Touch nt;
nt.id = touch.id + 100;
nt.state = touch.state + 100;
nt.time = touch.time + 100;
nt.x = touch.x + 100;
nt.y = touch.y + 100;
return nt;
}
在与C++相互传递类型时,Unity中,不能使用class来定义类型,只能使用struct,否则会造成Unity闪退。
原因分析:内存布局的一致性
- C++ :
- 在 C++ 中,结构体和类的内存布局是确定的,特别是在不包含虚函数的情况下。结构体和类的字段是按声明顺序紧凑排列的(除非有特殊的对齐要求)。
- C# :
- C# 的
struct
是值类型,内存布局与 C++ 的结构体非常相似。它们的字段在内存中是按顺序排列的,没有额外的间接层。 - C# 的
class
是引用类型,包含一个指向堆上对象的指针。这意味着引用类型在内存中有一个额外的间接层,与 C++ 的内存布局不一致。
- C# 的
C++内存布局示意图:
------------------------------------------
| id | x | y | time |
------------------------------------------
| 4 bytes | 4 bytes | 4 bytes | 8 bytes |
------------------------------------------
C#内存布局示意图:
struct:
---------------------------------------------------------
| id | x | y | time |
---------------------------------------------------------
| 4 bytes | 4 bytes | 4 bytes | 8 bytes |
---------------------------------------------------------
class:
栈:
--------------
| ptr | --->堆
--------------
堆:
---------------------------------------------------------
| id | x | y | time |
---------------------------------------------------------
| 4 bytes | 4 bytes | 4 bytes | 8 bytes |
---------------------------------------------------------