(下面的实际问题)
我经常将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;
Run Code Online (Sandbox Code Playgroud)
然后用以下方法调用它:
WriteOffsets(TypeInfo(TSecurityDescriptor));
Run Code Online (Sandbox Code Playgroud)
这很好地写了每个成员字段的大小和偏移量,所以我可以用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;
Run Code Online (Sandbox Code Playgroud)
但在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
Run Code Online (Sandbox Code Playgroud)
我知道这很丑陋,让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
}
Run Code Online (Sandbox Code Playgroud)
我得到这种输出:
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
};
Run Code Online (Sandbox Code Playgroud)
有没有办法让C++ Builder更加优雅和高效?理想情况下,我只提供类型(例如SECURITY_DESCRIPTOR),代码为其所有数据成员生成输出.
目前,与Delphi示例不同,我必须明确查询每个成员字段.我确实得到了我需要的输出,但它比Delphi要多得多.
我找不到让C++ Builder生成类似于Delphi中的扩展RTTI的RTTI的方法.有没有办法,使用C++(或实际上是C++ Builder)的更多扩展功能,例如模板和/或C++ 11(或C++ 14?)的新功能来更好地自动化,即我只是提供结构的名称和代码与Delphi相同?C++ Builder是否提供比普通C++提供的RTTI的基本一点点更好的RTTI?
我只对简单(Windows 32或64位)POD API结构的数据成员感兴趣,而不是在通用C++中使用的具有(可能是虚拟的)成员函数的类或结构中.