将C代码升级到VB.NET - Unioned Structures

时间:2011-02-03 17:17:56

标签: c vb.net

我正在尝试将Jim Kyle在90年代早期编写的btrieve代码升级到VB.NET,并且遇到了联合结构的问题。旧的C代码如下:

    typedef struct {
      union {
        struct {
          PGPTR   PgSeq;    // 00 - page number
          int     Usage;    // 04 - match with usage count
          int     Version;  // 06 - version code, <0 if owned
        } v5;
        struct {
          int     RecSig;   // 00 - 'FC'
          int     SeqNbr;   // 02 - always binary zeroes
          long    Usage;    // 04 - usage count
        } v6;
      } r1;
      int     PagSize;  // 08 - in bytes
    } FCRTOP;

到目前为止,我有:

    <StructLayout(LayoutKind.Explicit)> _
Structure FCRTOP
    <FieldOffset(0)> Public PgSeq As PGPTR
    <FieldOffset(4)> Public Usage As Short
    <FieldOffset(6)> Public Version As Short

    <FieldOffset(0)> Public RecSig As Short
    <FieldOffset(2)> Public SeqNbr As Short
    <FieldOffset(4)> Public Usage As Integer
End Structure

我遇到的一个问题是VB.NET不喜欢两个具有相同名称的结构变量(用法)。如果在C示例中(v5和v6)完成了重叠字段与唯一结构名称的分组,我缺少什么?

感谢您的帮助!

2 个答案:

答案 0 :(得分:7)

答案完全取决于你在做什么:

  • 如果您正在尝试为现有的非托管库创建托管接口(换句话说,请在VB.NET中编写代码或使用现有非代码调用代码的其他.NET语言.NET .dll),然后你就做对了。我将在第二个
  • 中解决这个问题
  • 如果您正在尝试创建现有非托管库的托管实现(即在.NET中重写现有的.dll并完全删除现有的.dll),那么您应该花钱将代码重构为面向对象而不是尝试复制结构等所需的时间。通常,只有在您有特别令人信服的理由时才应使用结构(它们是值类型);否则,您应该使用类(引用类型)并正确地将代码从过程迁移到面向对象。

如果您正在创建托管界面,则应该知道结构成员的命名将被忽略。这是元素的顺序和大小,这很重要。但是,这不是你的问题,因为你只是处理C定义结构的方式与VB.NET(和其他.NET语言)的方式之间的阻抗不匹配。由于union关键字只允许您将更大的结构分解为变量的逻辑块而不将子结构定义为独立的数据结构,因此需要进行一些按摩才能将其转换为.NET,这不允许这样的事情(同样,结构体不是在基于参考的面向对象语言(如VB.NET和C#)中封装信息的主要方法)。你必须采用子结构并将它们自己定义为结构,然后定义一个变量作为子结构,作为外部结构上的常规成员。

(顺便说一句,如果您按顺序声明成员,则无需使用StructLayoutKind.Explicit;使用Sequential会使其更容易阅读,如果它们已经按照正确的顺序排列。)< / p>

在那个有点冗长的回应之后,你正在寻找这样的东西:

<StructLayout(LayoutKind.Sequential)> _ 
Structure StructV5
    Public PgSeq As PGPTR
    Public Usage As Short
    Public Version As Short
End Structure 

<StructLayout(LayoutKind.Sequential)> _ 
Structure StructV6
    Public RecSig As Short
    Public SeqNbr As Short
    Public Usage As Integer
End Structure 

<StructLayout(LayoutKind.Explicit)> _ 
Structure FCRTOP
    <FieldOffset(0)>Public V5 as StructV5
    <FieldOffset(0)>Public V6 as StructV6
    <FieldOffset(8)>Public PagSize as Short
End Structure

您的另一个选择是保持您的结构不变(并添加PagSize成员),只需在Usage内更改v6的名称即可。但是,采用这种方法(使用显式结构声明)将为您提供更有意义的语法。

答案 1 :(得分:0)

VB.NET绝对没有这样的功能,所以我认为最好的办法是尝试以与.NET类型系统兼容的方式捕捉工会理念的“精神”。

免责声明:我对C的了解很少,所以我可能会误解C 中的工会的目的是什么。如果是这种情况,从我的建议中可以看出这一点。

所以,我认为你真正想要的是Structure包含64位,可以代表你的示例C代码中的v5v6,再加上PageSize的16位}。为了实现这一点,我要做的是存储4个Short值,并根据需要将它们组合起来(注意:我在下面概述的内容将是一个不可变类型;如果你需要使用公共读/写字段那么如果可能的话,我不知道如何实现这一点:

Structure FCRTOP
    Private a As Short
    Private b As Short
    Private c As Short
    Private d As Short

    Public ReadOnly PageSize As Short

    ' Possibly two constructors, one accepting PGTR, Short Short, Short, '
    ' the other accepting Short, Short, Integer, Short '

    Public ReadOnly Property V5 As V5
        Get
            Return New V5(a, b, c, d)
        End Get
    End Property

    Public ReadOnly Property V6 As V6
        Get
            Return New V5(a, b, c, d)
        End Get
    End Property
End Structure

Structure V5
    ' Constructor accepting 4 Short values '
    ' Properties that expose these values as PGTR, Short, Short'
End Structure

Stucture V6
    ' Constructor similar to V5 above '
    ' Properties that expose these values as Short, Short, Integer'
End Structure