gpt4 book ai didi

c# - 简单 union 转换示例 - C 到 C#

转载 作者:太空宇宙 更新时间:2023-11-04 03:52:30 25 4
gpt4 key购买 nike

我正在尝试在 C# 应用程序中使用用 C 编写的 DLL。我创建了一个简化的示例来复制我遇到的问题。

下面的 C 代码创建了一个 struct data 数组,并将数组指针分配给传递给 get_data()array 参数> 功能。 C# 代码应该是编码要在 C# 中使用的结构所需的样板代码,但它给我带来了问题。

C代码

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct data {
int32_t value;
union {
struct person {
uint8_t first[10];
uint8_t last[10];
} person;
struct number {
int32_t imaginary;
int32_t real;
} number;
} type;
};

int get_data(int count, struct data ***array)
{
int i;

/* allocate pointers */
*array = calloc(count, sizeof(struct data*));
if (*array == NULL)
return 1;

for (i = 0; i < count; i++) {
/* allocate data struct */
struct data *data = calloc(1, sizeof(struct data));
if (data == NULL)
return 2;

if ((i % 2) == 0) {
/* if even, its human */
data->value = i;
memcpy(data->type.person.first, "john", 4);
memcpy(data->type.person.last, "doe", 3);
} else {
/* if odd its a number */
data->value = i;
data->type.number.imaginary = -1;
data->type.number.real = i + 1;
}

(*array)[i] = data;
}

return 0;
}

C#代码

[DllImport("libdata.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 get_data(Int32 count, ref IntPtr array);

[StructLayout(LayoutKind.Sequential)]
public struct Person
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String first;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String last;
}

[StructLayout(LayoutKind.Sequential)]
public struct Number
{
public Int32 imaginary;
public Int32 real;
}

[StructLayout(LayoutKind.Explicit)]
public struct TypeUnion
{
[FieldOffset(0)]
public Person person;
[FieldOffset(0)]
public Number number;
}

[StructLayout(LayoutKind.Sequential)]
public struct Data
{
public Int32 value;
public TypeUnion type;
}

现在,当我运行我的测试程序时,我得到一个异常:

System.TypeLoadException was unhandled
Message=Could not load type 'WpfRibbonApplication1.TypeUnion' from assembly 'WpfRibbonApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.

我已经尝试了几种不同的方式来编码 Person 字符串,但无论我尝试哪种方式都会得到异常(使用 this 作为引用)。我错过了一些明显的东西吗?我能否获得一些帮助以正确读取在我的 C# 应用程序中的 C 函数中创建的数组?

编辑(根据 David Heffernan 的评论)

IntPtr arrayPtr = new IntPtr();
int count = 4;
int ret = LibData.get_data(count, ref arrayPtr);
Console.WriteLine("ret=" + ret);

for (int i = 0; i < count; i++)
{
IntPtr dataPtr = (IntPtr)Marshal.ReadIntPtr(arrayPtr) + (i * Marshal.SizeOf(typeof(IntPtr)));
Data data = (Data)Marshal.PtrToStructure(dataPtr, typeof(Data));
Console.WriteLine("value=" + data.value);
if ((i % 2) == 0)
{
// even is human
Console.WriteLine("first=" + data.type.first);
Console.WriteLine("last=" + data.type.last);
}
else
{
// odd is number
Console.WriteLine("imaginary=" + data.type.imaginary);
Console.WriteLine("real=" + data.type.real);
}
Console.WriteLine("");
}

最佳答案

错误消息告诉您不能用非对象字段覆盖对象字段。您正在用 int 覆盖 string

您无法通过使用 FieldOffset 复制 native union 来解决这个问题。在我看来,您有两个主要选择:

  1. 停止使用 union 并在 Data 结构中包含 PersonNumber 结构。
  2. 继续使用 union ,但要自己编码。使用 Marshal 类读取结构中的数据。例如,您可以使用 Marshal.ReadInt32 读取整数,使用 Marshal.Copy 读取字符数组等。

关于c# - 简单 union 转换示例 - C 到 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19639329/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com