问题:C#调用C++库函数时,传入参数是结构体Struct(按照1字节对齐),调试时发现传入参数赋值正常,但是传入到C++函数内,参数的值不对了。
C++定义结构体
typedef struct A{
int a;
int b;
bool c;
int d;
} __attribute__((packed)) A;
或
#pragma pack(1)
typedef struct A{
int a;
int b;
bool c;
int d;
}A;
C#定义的结构体
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct A
{
public int a;
public int b;
public bool c;
public int d;
}
结论:在bool变量前加一个[MarshalAs (UnmanagedType.I1)]或[MarshalAs (UnmanagedType.U1)]属性。再次调试,C#传入C++函数的结构体参数正确了。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct A
{
public int a;
public int b;
[MarshalAs (UnmanagedType.I1)]
public bool c;
public int d;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct A
{
public int a;
public int b;
[MarshalAs (UnmanagedType.U1)]
public bool c;
public int d;
}
原因:C#中bool是int型的占4字节,而C/C++里面的bool是byte型的占1字节,导致虽然添加了pack=1的属性,但是当由托管内存(C#)向非托管内存(C/C++)封送的时候是按照4字节来的,而原生C++代码是按照1字节来读取的。
先来看一下官方文档对C#中bool的解释Boolean 结构 (System) | Microsoft Learn
以及对类型UnmanagedType的解释UnmanagedType 枚举 (System.Runtime.InteropServices) | Microsoft Learn
扩展:
StructLayoutAttribute 类 (System.Runtime.InteropServices) | Microsoft Learn
StructLayoutAttribute.Pack 字段 (System.Runtime.InteropServices) | Microsoft Learn
StructLayoutAttribute.CharSet 字段 (System.Runtime.InteropServices) | Microsoft Learn
参考: