Есть ли Delphi-подобный расширенный RTTI в C ++ Builder? - PullRequest
0 голосов
/ 07 октября 2018

Контекст

( Актуальный вопрос ниже )

Легко в 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 генерировать RTTI, аналогичный расширенному RTTI в Delphi.Есть ли способ, используя более расширенные возможности C ++ (или фактически C ++ Builder), например шаблоны и / или новые функции C ++ 11 (или C ++ 14?), Чтобы автоматизировать это лучше, то есть я простопредоставить имя структуры и код делает то же самое, что Delphi?Предоставляет ли C ++ Builder более качественный RTTI, чем базовый RTTI, который обеспечивает обычный C ++?

Примечание

Меня интересуют только данные простых членов (Windows 32 или 64 бит) Структуры POD API, а не в классах или структурах с (возможно, виртуальными) функциями-членами, которые используются в общем C ++.

...