C ++ Builder中是否有类似Delphi的扩展RTTI?

时间:2018-10-07 14:15:32

标签: delphi c++builder

上下文

下面的实际问题

在Delphi中轻松

我定期将API标头转换为Delphi。有时结构对齐有问题,或者我错过了像#pragma pack(push, 1)这样的打包选项。要检查我是否具有正确的对齐方式和大小,我可以使用扩展RTTI的此简单功能在转换后的记录中显示偏移:

procedure WriteOffsets(Info: Pointer);
var
  LContext: TRttiContext;
  LType: TRttiType;
  LField: TRttiField;
begin
  LType := LContext.GetType(Info);
  if Assigned(LType) then
    if LType.TypeKind = tkRecord then
    begin
      Writeln(('  ' + LType.QualifiedName + ' = record ').PadRight(48),
        ' // size ', LType.TypeSize);
      for LField in LType.GetFields do
        Writeln(('    ' + LField.Name + ': ' + LField.FieldType.Name + ';').PadRight(48),
          ' // offset ', LField.Offset);
      Writeln('  end;');
      Writeln;
    end
    else
    begin
      Writeln(LType.QualifiedName, ' is not a record');
    end
  else
    Writeln('Invalid type');
end;

,然后调用:

WriteOffsets(TypeInfo(TSecurityDescriptor));

这很好地写了每个成员字段的大小和偏移量,因此我可以使用C ++ Builder生成的类似输出进行检查。该函数生成如下内容:

  Winapi.Windows._SECURITY_DESCRIPTOR = record   // size 20
    Revision: Byte;                              // offset 0
    Sbz1: Byte;                                  // offset 1
    Control: Word;                               // offset 2
    Owner: Pointer;                              // offset 4
    Group: Pointer;                              // offset 8
    Sacl: PACL;                                  // offset 12
    Dacl: PACL;                                  // offset 16
  end;

在C ++ Builder中不太容易

但是在C ++ Builder中,这并不是那么容易。我目前使用许多宏和简单的RTTI(typeid(x).name()),如下所示:

members.h

#ifndef MEMBERS_H
#define MEMBERS_H

void print_member(const char *type, const char *name, int offset)
{
    char buffer[256];
    sprintf(buffer, "    %s %s;", type, name);
    printf("%-48s // offset %d\n", buffer, offset);
}

#define print(member) \
    print_member(typeid(((type *)0)->member).name(), #member, offsetof(type, member))

#define start \
    printf("struct %-42s/\/ size %d\n{\n", typeid(type).name(), sizeof(type))

#define end \
    printf("};\n\n");

#endif

我知道这很丑陋,并且会使C ++纯粹主义者畏缩,但它确实有效。我在这样的简单测试程序中使用它:

#include "windows.h" // for the struct type I want to inspect
#include "members.h"

int main()
{    
    #define type SECURITY_DESCRIPTOR
    start;
        print(Revision);
        print(Sbz1);
        print(Control);
        print(Owner);
        print(Group);
        print(Sacl);
        print(Dacl);
    end;
    #undef type
}

我得到这种输出:

struct _SECURITY_DESCRIPTOR                      // size 20
{
    unsigned char Revision;                      // offset 0
    unsigned char Sbz1;                          // offset 1
    unsigned short Control;                      // offset 2
    void * Owner;                                // offset 4
    void * Group;                                // offset 8
    _ACL * Sacl;                                 // offset 12
    _ACL * Dacl;                                 // offset 16
};

问题

有没有一种方法可以使C ++ Builder的部分更加优雅和高效?理想情况下,我只提供类型(例如SECURITY_DESCRIPTOR),并且代码会为其所有数据成员生成输出。

当前,与Delphi示例不同,我必须显式查询每个成员字段。我确实获得了所需的输出,但是它比Delphi中的工作要多得多。

我找不到一种方法使C ++ Builder生成类似于Delphi中扩展的RTTI的RTTI。有没有办法使用C ++(或实际上是C ++ Builder)的更多扩展功能,例如模板和/或C ++ 11(或C ++ 14?)的新功能来更好地实现此目的,即我只提供结构的名称,并且代码与Delphi相同?与普通C ++提供的最基本的RTTI相比,C ++ Builder是否提供更好的RTTI?

注意

我只对简单的(Windows 32或64位)POD API结构的数据成员感兴趣,而不对普通C ++中使用的具有(可能是虚拟的)成员函数的类或结构感兴趣。

0 个答案:

没有答案