【问题标题】:How to translate a C struct to managed C# equivalent如何将 C 结构转换为托管 C# 等效项
【发布时间】:2017-06-12 11:36:27
【问题描述】:

我在 C 中有以下结构(示例):

typedef struct 
{
     int64      data_size;
     uint32      avgdelay;   
     int         esize;      
     void       *epayload;  
} stats_t;

托管的 C# 等效项如下:

[StructLayout(LayoutKind.Sequential, Size = 4)]
public struct stats_t
{
    public Int64 datasize;

    public UInt32 avgdelay;

    public Int32 esize;

    public IntPtr epayload;

}

当在调用的回调委托中使用 stats_t 类型的参数时,我发现有必要包含一个虚拟 UInt32 成员才能通过委托调用回调,以保留回调签名的字节模式

[StructLayout(LayoutKind.Sequential, Size = 4)]
public struct stats_t
{
    public Int64 datasize;

    public UInt32 avgdelay;

    public Int32 esize;

    public IntPtr epayload;

    /// dummy member for alignment
    public UInt32 dummy;

}

回调签名如下:

  int Callback_Proc( stats_t stats, void *user, int final, int error, int code);

回调的委托具有以下签名:

  public delegate int Callback_Proc(stats_t stats, IntPtr user, Int32 final, Int32 error, Int32 code);

我想知道为什么需要虚拟成员才能使回调起作用。如果没有 dummy,final 的值会转移到 error,而 error 的值会转移到 code。 感谢您的理解,并希望我的解释是有道理的。

【问题讨论】:

  • 您是否在相同位大小的操作系统和编译上同时编译和运行 C++ 和 C# 进程?乍一看,我可能会假设 C++ 进程是 64 位,而 C# 是 32 位,因此 IntPtr 将是 4 个字节,而 C++ void* 是 8 个字节。
  • 也许您在一个 64 位系统上,需要 64 位 quanta 来构建结构?你有什么理由不只在 C# 中使用一个类吗?
  • C++ 和 C# 都使用相同的 x86 位数。还有一个针对 C++ 和 C# 代码的 x64 单独构建。
  • Size = 4 太荒谬了,难以置信,结构比这大得多。我的水晶球说你实际上写了Pack = 4。不要那样做。

标签: c# callback delegates interop unmanaged


【解决方案1】:

那是因为 IntPtr 的大小。我假设你的 C++ 代码是为 64 位编译的,所以 C++ 代码期望的 void* 指针大小是 8 个字节,但是 .net 对 32 位有一个非常丑陋的偏好,如果你为 AnyCPU 编译,项目仍然有一个 (愚蠢)在编译选项中命名为“首选 32 位”的标志,因此即使代码在 64 位机器上执行,它也会以 32 位运行,导致指针长度为 4 个字节。

从项目中删除“首选 32 位”或显式编译为 x64,这应该可以解决您的问题。

【讨论】:

  • 谢谢,我分别有两个构建配置 x86 和 x64。不久前我摆脱了 AnyCPU 配置。
  • 那么问题可能出在 esize 上,你的 c++ 编译器将“int”视为“int32”还是“int64”?我说“可能是”,因为这会使有效载荷指针被移位并且无法读取...
  • 谢谢,我相信这可能是答案,因为在虚拟实现之前,我有回调使用 esize as Int64
猜你喜欢
  • 2015-05-27
  • 2012-04-08
  • 1970-01-01
  • 2022-06-11
  • 1970-01-01
  • 2013-07-31
  • 2018-12-07
  • 2017-02-14
  • 1970-01-01
相关资源
最近更新 更多