如何在 C# 中使用 struct 和 union

Posted

技术标签:

【中文标题】如何在 C# 中使用 struct 和 union【英文标题】:How use struct with union in c# 【发布时间】:2011-11-04 09:08:47 【问题描述】:

您好,我用 c# 编写了一个包装器,但遇到了一些问题。我在 C++ 中有这个结构。

typedef struct pjmedia_format

    pj_uint32_t id;
    pjmedia_type type;
    pjmedia_format_detail_type detail_type;
    union
    
    pjmedia_audio_format_detail aud;
    pjmedia_video_format_detail vid;
    char user[PJMEDIA_FORMAT_DETAIL_USER_SIZE];
     det;
 pjmedia_format;

这是指向此结构pjmedia_format的链接

在 c# 中我有这个:

[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_format

    public uint id;
    public pjmedia_type type;
    public pjmedia_format_detail_type detail_type;
    public det_t det;


[StructLayout(LayoutKind.Explicit)]
public struct det_t

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.Struct)]
    public pjmedia_audio_format_detail aud;
    [FieldOffset(36)]
    [MarshalAs(UnmanagedType.Struct)]
    public pjmedia_video_format_detail vid;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    [FieldOffset(60)]
    public char[] user;


[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_audio_format_detail

    public uint clock_rate;
    public uint channel_count;
    public uint frame_time_usec;
    public uint bits_per_sample;
    public int avg_bps;
    public int max_bps;


[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_video_format_detail

    public pjmedia_rect_size size;
    public pjmedia_ratio fps;
    public int avg_bps;
    public int max_bps;

当我想使用这个结构时,我得到了这个错误

System.Runtime.InteropServices.MarshalDirectiveException 未处理。 Message="方法签名与元素不兼容 PInvoke。"

我尝试使用一些属性,如大小或包装,但没有帮助(可能我用错了)。我单独测试了其他结构,例如pjmedia_video_format_detail 他们运作良好。有什么建议吗?

最好的问候 安德烈

【问题讨论】:

你为什么不做Interface @Shivan 对具有特定布局的 PInvoke 结构有什么帮助以任何方式 【参考方案1】:

既然这是一个工会,那不应该是:

[StructLayout(LayoutKind.Explicit)]
public struct det_t

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.Struct)]
    public pjmedia_audio_format_detail aud;
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.Struct)]
    public pjmedia_video_format_detail vid;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    [FieldOffset(0)]
    public char[] user;

即重叠? 另外,您可能需要将user 作为一个固定缓冲区,而不是一个数组。

【讨论】:

事实上ByValArray 很好【参考方案2】:

在 C++ 代码中,det 是 union。这意味着 所有 字段的偏移量为零,它们被覆盖。只需对 det_t 中的所有字段使用 [FieldOffset(0)] 更改您的 C# 声明以匹配。

【讨论】:

如果我更改为[FieldOffset(0)],我会收到另一个错误>System.ExecutionEngineException 我们很难为您调试。我们不知道界面的另一边是什么,也看不到您的调用代码。 如果我尝试在 c# 中使用这个function,就会调用这个异常我有这个[DllImport(PJSIP_DLL)] private static extern int pjmedia_vid_dev_get_info(int id, out pjmedia_vid_dev_info info); 调用约定怎么样?我猜 C++ 代码使用cdecl。您需要将CallingConvention = CallingConvention.Cdecl 添加到您的DllImport 属性中。 我添加了它,但我没有帮助:/ 如果我有 [FieldOffset(0)]... [FieldOffset(36)]... [FieldOffset(60)]... 这个函数有效,我在 pjmedia_vid_dev_info 中有一些数据,但在pjmedia_vid_dev_info.fmt[] 我只有空值

以上是关于如何在 C# 中使用 struct 和 union的主要内容,如果未能解决你的问题,请参考以下文章

C之 struct 和 union

结构体struct与联合体union的区别

联合体(union)的使用方法及其本质

Java中没有联合体union,应该如何实现union功能呢

struct和union区别

如何在 C# struct 中声明和使用固定大小的字符缓冲区