如何在类型A中定义类型B中的类型A和类型B中的类型B?

fru*_*ugi 7 c delphi types pointers record

我有两种类型.一个类型A和一个类型B.问题类型A包含类型B,类型B包含类型A.这样的事情将不起作用:

  type
    typeA = record
       test1 : typeB;
    end;
  type
    typeB = record
       test2 : typeA;
    end;
Run Code Online (Sandbox Code Playgroud)

编辑: 那不是我的设计.我将包含此类构造的C头文件(访问DLL)转换为delphi.

Edit2: "C++结构是AFAIR类的另一个名称.并且必须有指针,而不是值本身. - Arioch'1分钟之前"是的你是对的,它是一个类型的指针:

我在那里定义:

test1 : ^typeB;
Run Code Online (Sandbox Code Playgroud)

这会改变吗?

test1 : Pointer;
Run Code Online (Sandbox Code Playgroud)

Edit3: C结构:

/* DLPDFPAGE */
typedef struct dlpdfpage
{
    CosObj              Page;
    CosObj      PrintSelect;
    ASFixedRect         PageBBox;
    ASFixedRect         ContentBBox;
    struct dlpdfpage    *Next;
    PDRotate            Angle;
    struct dlpdfdoc     *Doc;
    DLPDFSTREAM         *Content;
    long                PageNumber;
    char                Complete;
    char                FontSubstituted;
    char                FontMM;
    char                FontBad;
} DLPDFPAGE;


/* DLPDFDOC */
typedef struct dlpdfdoc
{
    DLPDFINSTANCE       *dliInstance;
    PDDoc               pdDoc;
    CosDoc              cosDoc;
    DLPDFOUTLINE        *Outlines;
    char                *PDFFileName;
    char                *PDFPostFileName;
    DLPOS               LastPageEnd;
    DLPOS               BeforeDef;
    ASFixedRect         DocBBox;
    long                PageCount;
    long                PageTreeWidth;
    long                PageTreeDepth;
    long                PageTreeDepthUsed;
    DLPDFPAGETREEARRAY  *AllPages;
    DLPDFFONTLIST       *AllFonts;
    DLPDFFORMLIST       *AllForms;
    DLPDFFORMLIST       *AllColors;
    DLPDFIMAGELIST      *AllImages;
    DLPDFSPOTCOLORLIST  *AllSpotColors;
    DLPDFSPOTCOLORLIST  *AllPatterns;
    DLPDFEXTGSTATELIST  *AllExtGStates;
    DLPDFPAGE           *PageList;
    DLPDFPAGE           *LastPage;
    DLPDFDEST           *DeferedDests;
    DLPDFSIGNATURE      *signatureHolder;
    struct dlpdfacroform *AcroFormBase;
    CosObj              PatternColorObj,
                        PatternColorRGBObj,
                        PatternColorCMYKObj,
                        PatternColorGrayObj,
            PrintSelect,
            PrintSelectCriteria;
    CosObj      IdentH, IdentV;
    ASAtom              DocumentEncoding;
    long                FontCount;
    long                FormCount;
    long                PatCount;
    long                ImageCount;
    char                Compress;
    char                Linearize;
    char                PageTreeComplete;
    char                EmbedFonts;
    char                PatternColorsDefined;
    char                MakeThumbNails;
    ASBool              psSevenBitSafe;
    ASInt32             EncryptKeyByteCount;

    char                condenseResDicts;
    CosObj              resourceDict;  

    ASInt16             pdfMajorVer;    
    ASInt16             pdfMinorVer;    

    DLPDFINCLUDEDRES    *InclRes;       

    DLPDFSPOTCOLORLIST  *AllShadings;
    long                ShadeCount;

} DLPDFDOC;
Run Code Online (Sandbox Code Playgroud)

Cos*_*und 14

你误解了那些C结构所代表的含义.那是因为a record是一个值类型:它存储在你声明变量的地方.那么让我们做一些级别的递归声明,你就会理解我的意思; 假设两个结构不完全相同:

type
  TA = record
     test1 : TB;
     SomethingElseFromA: Byte;
  end;

  TB = record
     test2 : TA;
     SomethingElseFromB: Byte;
  end;   
Run Code Online (Sandbox Code Playgroud)

结构TA可以改写为:

type
  TA = record
    // Replaced test1 : TB with the actual content of TB, because that's
    // what a record means.
    test1_test2: TA;
    test1_SomethingElseFromB: Byte;

    SomethingElseFromA: Byte;
  end;
Run Code Online (Sandbox Code Playgroud)

当然,我们现在已经将一个很好的递归包含在TA记录中,这有点类似于:

  TA = record
    // Replaces test1_test: TA
    test1_test2: TA; // Oops, still not fixed, need to do it again...
    test1_SomethingElseFromB: Byte;
    SomethingElseFromA: Byte;

    test1_SomethingElseFromB: Byte;
    SomethingElseFromA: Byte;
  end;
Run Code Online (Sandbox Code Playgroud)

您可能希望使用引用类型来获得看起来相似的内容,但它并不相似.引用类型始终是指针,因此它是固定大小; 编译器可以毫无问题地分配它.这将是有效的,使用指针记录:

type
  pTypeB = ^typeB;
  pTypeA = ^typeA;

  typeA = record
     test1 : pTypeB;
  end;

  typeB = record
     test2 : pTypeA;
  end;
Run Code Online (Sandbox Code Playgroud)

或者你可以使用类; 这也是出于同样的原因,类是引用类型; 它们的工作方式与指针相同.声明指针类型的变量时,编译器会分配SizeOf(Pointer)字节.


既然你已经发布了C结构,我可以说它们对我来说太长了以后尝试完整的翻译,但我可以提出一些建议:你应该在一个Type块中声明所有类型; 不要Type在每个类型声明之前写入.这允许您在记录类型之前创建指针类型,如下所示:

Type
  PMyRecord = ^TMyRecord;

  // Somewhere in the same Type block
  TMyRecord = record
  end;
Run Code Online (Sandbox Code Playgroud)

对于每个需要指针到记录的类型,首先在Type关键字之后声明指针,这样就更简单了.接下来,您需要识别C指针.如果*数据类型的名称和字段的名称之间有一个,那就是指针.这通常是这样写的:

int *PointerToSomeInt;
Run Code Online (Sandbox Code Playgroud)

但那些也同样有效:

int * PointerToSomeInt;
int* VarName1, * VarName1, * VarName3; // Three pointers to integer.
Run Code Online (Sandbox Code Playgroud)

最后,您需要处理对齐问题.如果可以的话,检查C侧结构的大小,然后检查Delphi侧的大小:你应该得到相同的大小.如果不这样做,您应该{$ALIGN}在结构声明之前尝试几个随机编译器指令并重复,直到找到正确的对齐方式.如果所有其他方法都失败了,你需要找到错误的东西(Delphi方面哪些字段的排列方式不同)并加入一些对齐字节来人工修复它.

  • 特别是这很重要:"你应该在一个Type块中声明所有类型,不要在每个类型声明之前写入Type." (2认同)

And*_*and 11

也许最好的解决方案是重新考虑设计.但是您可能也对所谓的类的前向声明感兴趣:

type
  TTypeB = class;

  TTypeA = class
    test: TTypeB;
  end;

  TTypeB = class
    test: TTypeA;
  end;      
Run Code Online (Sandbox Code Playgroud)

SIC!这仅适用于类,而不适用于记录.

  • 是的,@ Arioch,类和接口都可以有前向声明.Cosmin的回答演示了*指针*前向声明.我不确定您认为变体记录(在1974年Pascal意义和2013 Delphi意义上,因为它们是相同的)会增加这个主题. (2认同)