我在处理 boolean 类型以及在 C# 和 C 之间来回编码结构时遇到一些问题。我对 C 很生疏,但希望这部分没有什么严重错误。
据我所读/所见,.NET Boolean 和C# bool 类型为 4 个字节长,而C 类型 bool 仅 1 个字节。由于内存占用的原因,我不知道在 C 代码中使用定义的 BOOL 4 字节版本。
这是一些简单的测试代码,希望能让我的问题清楚:
C 代码:
typedef struct
{
double SomeDouble1;
double SomeDouble2;
int SomeInteger;
bool SomeBool1;
bool SomeBool2;
} TestStruct;
extern "C" __declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs);
__declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs)
{
return structs;
}
我使用以下定义在 C# 中调用此代码:
[StructLayout(LayoutKind.Explicit)]
public struct TestStruct
{
[FieldOffset(0)]
public double SomeDouble1;
[FieldOffset(8)]
public double SomeDouble2;
[FieldOffset(16)]
public int SomeInteger;
[FieldOffset(17), MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[FieldOffset(18), MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
[DllImport("Front.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr TestGetBackStruct([MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] TestStruct[] structs);
这是 C# 中的实际测试函数:
[Test]
public void Test_CheckStructParsing()
{
var theStruct = new TestStruct();
theStruct.SomeDouble1 = 1.1;
theStruct.SomeDouble2 = 1.2;
theStruct.SomeInteger = 1;
theStruct.SomeBool1 = true;
theStruct.SomeBool2 = false;
var structs = new TestStruct[] { theStruct };
IntPtr ptr = TestGetBackStruct(structs);
var resultStruct = (TestStruct)Marshal.PtrToStructure(ptr, typeof(TestStruct));
}
这在某种意义上是有效的,我确实得到了一个结构(使用调试器来检查它),但值完全错误。 IE。编码根本不起作用。我尝试了不同版本的 C# 结构,但没有成功。这是我的问题(1 和 2 最重要):
- C 函数是否适合此目的?
- 如何正确编写结构体,以便将结构体中的正确值返回到 C#?(是否有必要使用 StructLayout(LayoutKind.Explicit) 定义结构体属性使用 FieldOffset 值还是我可以使用 StructLayout(LayoutKind.Sequential) 代替)?
- 由于我在 C 中返回一个指向 TestStruct 的指针,因此我想应该可以在 C# 中返回 TestStructs 数组。但这似乎无法使用 Marshal.PtrToStructure 函数实现。是否可以通过其他方式实现?
- 显然,可以通过使用相同的 FieldOffset 属性值让多个结构体字段指向相同的内存分配,从而使用 C 中称为“union ”的东西。我理解这一点,但我仍然还不知道这种情况何时有用。请赐教。
- 有人可以推荐一本关于 C# P/Invoke to C/C++ 的好书吗? 我有点厌倦了在网络上到处获取信息。
非常感谢您对这些问题的帮助。我希望他们不要太多。
最佳答案
停止使用 LayoutKind.Explicit
并删除 FieldOffset
属性,您的代码将正常工作。您的偏移量未正确对齐字段。
public struct TestStruct
{
public double SomeDouble1;
public double SomeDouble2;
public int SomeInteger;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
在 C# 中声明该函数,如下所示:
public static extern void TestGetBackStruct(TestStruct[] structs);
默认编码将与您的 C++ 声明匹配(您的代码实际上是 C++ 而不是 C),但您必须确保在调用函数之前在 C# 代码中分配 TestStruct[]
参数。通常,您还会将数组的长度作为参数传递,以便 C++ 代码知道有多少个结构。
请不要尝试从函数返回结构数组。使用 structs
参数作为输入/输出参数。
据我所知,没有一本书强调 P/Invoke。这似乎是一种黑魔法!
关于c# - 在结构中使用 boolean 值的一些 P/Invoke C# 到 C 编码问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6612030/