unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;type
  TRec=record
    a: byte;
    b: string;
    c: integer;
    d: string;
    e: double;
    f: string;
    g: double;//TDateTime;
    h: real;
    i: byte;
    j: byte;
  end;  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    Button9: TButton;
    Button10: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Button9Click(Sender: TObject);
    procedure Button10Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;function GetSize(const s: string): Integer;var
  Form1: TForm1;
  r: TRec;
  pr: ^TRec;
  p: Pointer;implementation{$R *.DFM}function GetSize(const s: string): Integer;
var
  SizePointer: Pointer;
begin
  if Pointer(s)<>nil then
  begin
    SizePointer := Pointer(Integer(Pointer(s))-4);
    result := Integer(SizePointer^);
  end
  else
    result := 0;
end;procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
  r.a:=1;
  r.b:='234567111111111111111111111';
  //i:=sizeof(r.b);
  r.c:=3;
  r.d:='4';
  r.e:=5.0;
  r.f:='6';
  r.g := now;
  r.h :=8.0;
  r.i :=9;
  r.j :=10;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r));                          //a
  (sender as Tbutton).caption := IntToStr(Integer(p^));
end;procedure TForm1.Button2Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r)+4);                         //b   ??+4
  (sender as Tbutton).caption := String(p^);
end;procedure TForm1.Button3Click(Sender: TObject);
begin                                                 //c
  p :=Pointer(Integer(@r)+8);
  (sender as Tbutton).caption := IntToStr(Integer(p^));
end;procedure TForm1.Button4Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r)+12);                       //d
  (sender as Tbutton).caption := String(p^);
end;procedure TForm1.Button5Click(Sender: TObject);
begin                                                //e
  p :=Pointer(Integer(@r)+16);
  (sender as Tbutton).caption := floattostr(double(p^));
end;procedure TForm1.Button6Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r)+24);                       //f
  (sender as Tbutton).caption := String(p^);
end;procedure TForm1.Button7Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r)+32);                      //g
  (sender as Tbutton).caption := DateTimeToStr(TDateTime(p^));
end;procedure TForm1.Button8Click(Sender: TObject);
begin
  p :=Pointer(Integer(@r)+40);                      //h
  (sender as Tbutton).caption := floattostr(double(p^));//IntToStr(Integer(p^));
end;procedure TForm1.Button9Click(Sender: TObject);
var
  a: ^byte;
begin                                                //i
  p :=Pointer(Integer(@r)+48);
  (sender as Tbutton).caption := IntToStr(Integer(p^));
  a := p;
  (sender as Tbutton).caption := IntTostr(a^);
end;procedure TForm1.Button10Click(Sender: TObject);
begin                                              //j
  p :=Pointer(Integer(@r)+49);                          //??+1
  (sender as Tbutton).caption := IntToStr(Byte(p^));
end;end.在访问r.f之前,我可以断定记录体中的每个域其实就是一个32位指针或者是64位指针。但是访问到后面的域时,这样的解释就好像不对了。希望大家可以给我一个合理的解释。

解决方案 »

  1.   

    很简单的,就是在指针上加上这个域偏移量就行了。
    比如:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      a: ^TRec;
    begin
      new(a);
      a.a := 100;
      a.b := 'abcd';
      a.c := 300;
      a.d := 'dddd';
      a.e := 1000.230;
      caption := string(pointer(integer(a)+12)^);
      dispose(a);
    end;这中间通过a的指针访问了域d. 其中指针加上了12是因为编译器在进行编译的时候要考虑字节对齐,所以a域虽然只占了一个字节但是还是分配了4个字节。
    b域是字符串指针占4个字节,c域整数占4个字节。所以访问d域加上12即可。
    编译器在编译的时候可以指定对齐的字节数. 
    设定方法: project --> option --> record field alignment 默认为8 .
    如果该成1的话前面的偏移加9 即可。
      

  2.   

    findcsdn(findcsdn) 可以解释清楚点吗?
    就是编译器在进行编译的时候是怎样考虑字节对齐?有什么规律?
    还有我贴出来的,你可以试下吗?
    有时记录里面的域之间的偏移量是4,有时又是8,有时又是1.
    其中我访问b域时,我只需在a域的地址上加4就可以,
    但是我访问j域时,我却需在i域的地址上加1,访问的数据才正确,
    如果是字节对齐的话,又怎么解释?
    而且,我访问b,j域时,a,i类型时一致的,我认为象这种类型,
    应该32位指针足够访问这种类型的数据了。
      

  3.   

    而且我访问f域时,我假设e是一个64位的指针,那么它加8的偏移量是对的。
    但是我在访问g域时,偏移量竟然不是4,而是8.我觉得这样很矛盾。因为前面我访问一个域(假设为1域时),那么它前面的一个0域同样是string类型,但是它们的偏移量是4.
      

  4.   

    字节对齐不会总是与前一个域所占有的空间对齐吧?
    但是这样字节对齐又明显不对,因为我如果有一个string类型的域,那它的偏移量也是4,不管它的长度有多长,当然在我贴出来的代码中,也试过这种类型的偏移量是8.现在也没办法解释它是如何通过4个字节去访问这个string类型的域。但是把它看成是一个域,这个现象就变得合情合理。可是有些情况又不能得到很好的解释。
    不过,我觉得如果把域看成是一个指针,这样如果定义一个这种类型的数组,
    我想它会省下很多存储空间的。
      

  5.   

    packaged 的record没有自动对齐,但是符合你的需求。
      

  6.   

    前段时间没有时间,今天又把这个问题研究了一遍,有点收获,特公布出来。
    根据delphi的帮助说明:字节对齐的行为为了优化程序的运行速度。因为p2-p4的cpu的数据总线都是32位的(4byte),所以数据访问尽量按照4字节的倍数对齐。
    我总结了几条编译器进行字节对齐的规律:
    1. 在字节对齐的情况下delphi的所有纪录数据类型的占用字节数只能1,2,4,8等4中情况。其他情况如字符串和内存块用指针来表示,所有指针4个字节。
    2. 编译器可以设定字节对齐的字节数,比如delphi默认的字节数是8个字节。这8个字节的意思是什么呢。好比一个写字板每行只能写8个字一样,就是说纪录的逻辑情形就是有多个8字节的行组成的,也就是一个( 8 x N )的一个矩形
    而且规定一个域只可能在一行中,不能在两行中。3。那么compiler怎么在这一行行的8个字节中分配各个纪录域的呢?是这样的。前面说过了,数据域只可能1,2,4,8,如果不是的会加0补齐,而且数据与不能占两行.算法好像有点复杂,不过如果用笔在纸上画一下也就出来了,不过这理面还要4字节对齐的问题。比如三个域分别为(1,1,4)那么显然前两个1占用前两个字节,然后空两个字节,然后后面的4字节为第三域。说了一大堆不知道说明白没?
      

  7.   

    我将楼主列的纪录的内存结构画了一下,欢迎讨论。
    1。各种数据类型的大小;
     byte(1); string指针(4);  integer(4); double(8); real(6);
    对齐时: real(8);|1234|5678|
    |a000|--b-|
    |-c--|--d-|
    |----e----|
    |-f--|0000|   因为g为8字节该行只剩余4字结了。
    |----g----|
    |--h----00|
    |ij0000000|我对该纪录的各种变种作了测试均符合上面的规律。
      

  8.   

    太多谢你了,你那个图很形象。
    不过我有一点要补充的,就是real类型的size跟double类型是一样大小的。
    delphi的帮助是这么写的。
      

  9.   

    我说的把记录的域看成是指针的观点是错的。
    一开始这样认为主要是不清楚string实则是一个指针,
    不过有一点也是不明白,delphi是怎么实现这样一个指针,
    因为string类型不象c语言的pChar类型,还希望 findcsdn(findcsdn) 同志能再指教一下。
      

  10.   

    应该说delphi的string是没有结束符的,但是它怎么知道这个string的大小?