德尔福:记录领域的偏移 [英] Delphi: Offset of record field

查看:164
本文介绍了德尔福:记录领域的偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找在Delphi记录中获取字段偏移量的方法。以下2种方法有效,但我希望能够更清洁。基本上我会喜欢第三次showmessage工作。任何想法?

I'm looking for ways to obtain the offset of a field in a Delphi record. These 2 following methods work but i was hoping for a cleaner way. Basically i would have liked the third showmessage to work. Any ideas?

type
 rec_a=record
  a:longint;
  b:byte;
  c:pointer;
 end;

{$warnings off}
function get_ofs1:longint;
var
 abc:^rec_a;
begin
 result:=longint(@abc.c)-longint(abc);
end;
{$warnings on}

function get_ofs2:longint;
asm
 mov eax,offset rec_a.c
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 showmessage(inttostr(get_ofs1));
 showmessage(inttostr(get_ofs2));
// showmessage(inttostr(longint(addr(rec_a.c)))); // is there a way to make this one work?
end;

编辑:
好​​的,下面的答案工作正常,谢谢!作为参考,以下是各种选项的汇编器输出:

edit: Alright, the below answer works fine, thanks! For reference, here's the assembler output for the various options:

---- result:=longint(@abc.c)-longint(abc); ----
lea edx,[eax+$08]
sub edx,eax
mov eax,edx

---- mov eax,offset rec_a.c ----
mov eax,$00000008

---- result:=longint(@rec_a(nil^).c); ----
xor eax,eax
add eax,$08

edit2 :看起来与以前的问题重复:以前的类似问题, RRUZ如下。如图所示,另一种方法是声明一个全局变量并使用它,如下所示。奇怪的是,编译器仍然无法在编译时分配正确的值,如汇编器输出中所见,因此无论是效率还是可读性,最好使用nil方法。

edit2: looks like this is a duplicate of a previous question: previous similar question as noted below by RRUZ. As shown there, another method is to declare a global variable and use it as follows. Strangely enough the compiler still isnt able to assign the proper value at compile time as is seen in the assembler output, so for both efficiency and readability it`s better to use the nil method.

---- var ----
----  rec_a_ofs:rec_a; ----
---- ... ----
---- result:=longint(@rec_a_ofs.c)-longint(@rec_a_ofs); ----
mov eax,$0045f5d8
sub eax,$0045f5d0

编辑3:好的修改代码,所有知道的方式来完成这个。请注意,第3,第4和第5(类方法)方式生成的汇编代码是否相同,无论是否内联。选择你最喜欢的方式,当你做这些东西!

edit3: Ok revised code with all know ways to accomplish this. Note that the assembler code generated for the 3rd, 4th, and 5th (class method) ways is identical, whether they are inlined or not. Choose your favorite way when you get to do this stuff!

type
 prec_a=^rec_a;
 rec_a=record
  a:longint;
  b:byte;
  c:pointer;

  class function offset_c:longint;static;inline;
 end;

//const
// rec_a_field_c_offset=longint(@rec_a(nil^).c); // no known way to make this work

{$warnings off}
function get_ofs1:longint;inline;
var
 abc:^rec_a;
begin
 result:=longint(@abc.c)-longint(abc);
end;
{$warnings on}

function get_ofs2:longint;
asm
 mov eax,offset rec_a.c
end;

function get_ofs3:longint;inline;
begin
 result:=longint(@rec_a(nil^).c);
end;

function get_ofs4:longint;inline;
begin
 result:=longint(@prec_a(nil).c);
end;

class function rec_a.offset_c:longint;
begin
 result:=longint(@prec_a(nil).c);
end;

var
 rec_a_ofs:rec_a;

function get_ofs6:longint;inline;
begin
 result:=longint(@rec_a_ofs.c)-longint(@rec_a_ofs);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 showmessage(inttostr(get_ofs1));
 showmessage(inttostr(get_ofs2));
 showmessage(inttostr(get_ofs3));
 showmessage(inttostr(get_ofs4));
 showmessage(inttostr(rec_a.offset_c));
 showmessage(inttostr(get_ofs6));
// showmessage(inttostr(rec_a_field_c_offset));
end;


推荐答案

我一直使用这种方法:

Offset := Integer(@rec_a(nil^).c);

不要使用 nil ^ 4GB,那么您有更大的问题!

Don't let the use of nil^ put you off, it's perfectly safe. And don't worry about 64 bit pointer truncation. If you have a record whose size is >4GB then you have bigger problems!

这篇关于德尔福:记录领域的偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆