type
  Ta=record
     a:string;
     c:integer;
     b:Double;
  end;
var
  t:Ta;
begin
  ShowMessage(IntToStr(SizeOf(t)));
end;结果为16.
而修改一下:type
  Ta=record
     c:integer;
     b:Double;
     a:string;
  end;
var
  t:Ta;
begin
  ShowMessage(IntToStr(SizeOf(t)));
end;结果为24,只是把记录定义中的a:string位置变一下,结果就不一样了。请问是什么原因呢?

解决方案 »

  1.   

    type 
      Ta=packed record 
        a:string; 
        c:integer; 
        b:Double; 
      end; 
    var 
      t:Ta; 
    begin 
      ShowMessage(IntToStr(SizeOf(t))); 
    end; type 
      Ta=packed record 
        c:integer; 
        b:Double; 
        a:string; 
      end; 
    var 
      t:Ta; 
    begin 
      ShowMessage(IntToStr(SizeOf(t))); 
    end; 
      

  2.   

    不带packed关键字的结构体表明编译器编译时要求进行字对齐,而带packed关键字的结构体表明编译器编译该结构体时不需要进行字对齐,这种方式对结构体中的字段访问会比第一种方式慢但是更节约空间
      

  3.   

    结构体对齐的原因.而且,string这种类型,不好判断它占多少字节.
    除非你用short string,也就是象:string[10] 这样.或者 a: array[0..9] of Char;
      

  4.   

    DELPHI中记录的存储方式
          在DELPHI中,我们用record关键字来表明一个记录,有时候,我们还会看到用packed record来声明的记录,这二者的区别就在于存储方式的不同。
          在windows中,内存的分配一次是4个字节的,而Packed按字节进行内存的申请和分配,这样速度要慢一些,因为需要额外的时间来进行指针的定位。因此如果不用Packed的话,Delphi将按一次4个字节的方式申请内存,因此如果一个变量没有4个字节宽的话也要占4个字节!这样浪费了一些空间,但提高了效率。所谓鱼与熊掌不可兼得。
           例如一个记录,以,sizeof(wudi)应该得到8。而如果使用packed关键字,那么sizeof(wudi)则得到5。   type wudi= record
         age : integer;
         sex : shortint;    
       end;      其中age是integer类型,正好4个字节,而sex是showint类型,占用一个字节,但基于4字节得内存分配方式,这里它也将占用4个字节
      

  5.   

    packed我是明白的,现在是想知道string类型的变量在不同的位置为什么结果不一样。
      

  6.   

    Ta=record
      a:string;
    end
    如果测试下上面这个结果,大小是4,证明string类型是4个字节的,因为存储的是一个指针。但我就不明白加上其他类型后,放在不同的位置就有不同的结果。
      

  7.   

    字节对齐导致得.
    记录(结构)中,成员间需要进行字节对齐.(如果只有一个成员,那么就不需要对齐.)
    Delphi7及以后得版本,默认都是以8字节对齐的.因此,默认情况,当记录中的成员数大于一个后,记录中进行字节对齐,那么记录
    的大小必然是 8 的整数倍.Delphi 7中修改默认对齐方式:
    Project -> Options -> Compiler -> Record field alignment.Delphi 2009中修改默认对齐方式:
    Project -> Options -> Delphi Compiler -> Compiling -> Code generation -> Record field alignment当然,也可以在代码中使用编译开关{$A} {$A2} {$A4} {$A8}
      

  8.   

     Ta=record 
        a:string; //4
        c:integer; //4
        b:Double; //8
      end; type 
      Tb=record 
        c:integer;//4 
        b:Double; //8
        a:string; //4
      end; 这是编译的编译处理问题,我是这样理解的:
    机器码为4字节,对于大于四字节比如8字节数据,从机器的偶数(也可能奇数地址)开始分配高字节和低字节。
    对于ta来说,从偶数地址开始分配空间(假设为编译器原则):
    a 0(地址)
    c 1
    b 2
      3
    所以为16字节
    对于tb来说
    c  0 
       1(空)
    b  2
       3
    a  4
       5(空,考虑下一数据不确定)所以为24字节这只是我个人的看法,望高手指正
      

  9.   


    由于默认是按8字节对齐的,所以第一种定义
      Ta=record 
        a:string;     //4字节
        c:integer;    //4字节
        b:Double;     //8字节
      end; 
    前a+c占用空间正好8字节,已经对齐。总占用空间16字节。而第二种定义
      Ta=record 
        c:integer;    //4字节
        b:Double;     //8字节
        a:string;     //4字节
      end; 
    在c和a之后,都需要添加4个字节来对齐,所以比第一种定义占的空间要大,总占用空间24字节。
      

  10.   

    The $A directive controls alignment of fields in Delphi record types and class structures.
    In the {$A1} or {$A-} state, fields are never aligned. All record and class structures are packed.
    In the {$A2} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on word boundaries.
    In the {$A4} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on double-word boundaries.In the {$A8} or {$A+} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on quad word boundaries.
    Record type field alignment is described in the Delphi Language Guide. See Record types.
    Regardless of the state of the $A directive, variables and typed constants are always aligned for optimal access. In the {$A8} state, execution will be faster.
      

  11.   

      Ta=packed record 
        a:string; 
        c:integer; 
        b:Double; 
      end;
    =======>
    string,存放的是指针,占用4字节长度,要求8字节边界对齐,这是第一个字段,故已经放在8字节边界的地址中。
    integer,占用4字节长度,要求4字节边界对齐,故刚好接上字段即可,无需调整。
    double,占用8字节长度,要求8字节边界对齐,故刚好接上字段即可,无需调整。
    4+4+8=16,刚好是最大对齐要求double的8字节的整数倍(2×8=16),故总的record尺寸不需要调整,最终就是16。
    ==================================================
      Ta=record 
        c:integer;
         b:Double;  
         a:string; 
      end; 
    ========>
    integer,占用4字节长度,要求4字节边界对齐,但这是第一个字段,故已经放在8字节边界的地址中。
    double,占用8字节长度,要求8字节边界对齐,故先要插入4个无用的字节,然后放入double。
    string,存放的是指针,占用4字节长度,要求8字节边界对齐,故刚好接上字段即可,无需调整。
    4+4+8+4=20,但不是最大对齐要求double的8字节的整数倍,故delphi还会对其进行延长为3×8=24,所以最终为24。
      

  12.   

    楼上第2部分的分析不正确。
    procedure TForm1.Button1Click(Sender: TObject);
    type
      Ta=record
        c:integer;
        b:Double;
        a:string;
      end;
    var
      x: Ta;
    begin
      Label1.Caption := IntToStr(SizeOf(x));  Label2.Caption := IntToHex(Integer(@x.c), 8);
      Label3.Caption := IntToHex(Integer(@x.b), 8);
      Label4.Caption := IntToHex(Integer(@x.a), 8);end;输出结果:
    24
    0012F6FC
    0012F704
    0012F70C可见是:
    8+8+8=24
    呵呵
      

  13.   

    c:integer:0012F6FC-0012F6FF 
    填充:      0012F700-0012F703
    b:Double: 0012F704-0012F70B
    a:string: 0012F70C-0012F70F
    填充     : 0012F710-0012F713
    填充的部分是不存放有效数据的,也不算作field的有效部分,故不会成为任何field的首地址。
      

  14.   

    比较完整的说明:
    When a record type is declared in the {$A+} state (the default), and when the declaration does not include a packed modifier, the type is an unpacked record type, and the fields of the record are aligned for efficient access by the CPU. The alignment is controlled by the type of each field and by whether fields are declared together. Every data type has an inherent alignment, which is automatically computed by the compiler. The alignment can be 1, 2, 4, or 8, and represents the byte boundary that a value of the type must be stored on to provide the most efficient access. The table below lists the alignments for all data types.Type alignment masks 
    Type Alignment 
    Ordinal types size of the type (1, 2, 4, or 8)
    Real types 2 for Real48, 4 for Single, 8 for Double and Extended
    Short string types 1
    Array types same as the element type of the array.
    Record types the largest alignment of the fields in the record
    Set types size of the type if 1, 2, or 4, otherwise 1
    All other types determined by the $A directive.
    To ensure proper alignment of the fields in an unpacked record type, the compiler inserts an unused byte before fields with an alignment of 2, and up to three unused bytes before fields with an alignment of 4, if required. Finally, the compiler rounds the total size of the record upward to the byte boundary specified by the largest alignment of any of the fields.
    If two fields share a common type specification, they are packed even if the declaration does not include the packed modifier and the record type is not declared in the {$A-} state. Thus, for example, given the following declarationtype
      TMyRecord = record
        A, B: Extended;
        C: Extended;
      end;A and B are packed (aligned on byte boundaries) because they share the same type specification. The compiler pads the structure with unused bytes to ensure that C appears on a quadword boundary.When a record type is declared in the {$A-} state, or when the declaration includes the packed modifier, the fields of the record are not aligned, but are instead assigned consecutive offsets. The total size of such a packed record is simply the size of all the fields. Because data alignment can change, it's a good idea to pack any record structure that you intend to write to disk or pass in memory to another module compiled using a different version of the compiler.
      

  15.   

    type
      Ta = record
        c: Integer;
        b: Int64; //为了便于观察,将Double改为Int64进行试验
        a: string;
      end;
    var
      t:Ta;
    begin
      t.c := 199;
      t.b := 2987;
      t.a := 'jjj';
      ShowMessage(IntToStr(SizeOf(t)));
    end.
    ===================
    在watch窗口观察内存:
    t: $C7 $00 $00 $00 $00 $00 $00 $00 $AB $0B $00 $00 $00 $00 $00 $00 $F8 $1F $D5 $00 $00 $00 $00 $00 可见确实如此。