T1 = record
    b1,b2:Boolean;
    ID:Integer;
    v2:Extended; // 10
  end;  T2 = record
    b1,b2:Boolean;
    ID:Integer;
    v1:array [0..9] of Byte; // 10
  end;SizeOf(Extended) = 10SizeOf(T1) = 24 ?????
SizeOf(T2) = 20可以将以上两个结构写入文件中用 UltraEdit 看。
T1 中最后多出了4个字节,我无法理解。
我一直以后,是4字节一分配。
够的话,接在后面,
不够的时候,再开4字节。哪位高手能解释,为什么两个结构体,得到的大小不一样。
(Delphi2007 + WinXP)

解决方案 »

  1.   

    Extended是按64位对齐的,所以它对齐后是16字节
      

  2.   

    和编译开关 也有关系
    Record field alignment 
     Controls alignment of fields in Delphi record types and class structures. Click the down-arrow to select from the possible values: If you select option Off (equivalent to {$A1}) or disable the option (equivalent to {$A-}), fields are never aligned. All record and class structures are packed. If you select Byte (equivalent to {$A2}), fields in record types that are declared without the packed modifier and fields in class structures are aligned on byte boundaries. If you select Word (equivalent to {$A2}), fields in record types that are declared without the packed modifier and fields in class structures are aligned on word boundaries. If you select Double Word (equivalent to {$A4}), fields in record types that are declared without the packed modifier and fields in class structures are aligned on double-word boundaries. If you select Quad Word (equivalent to {$A8} or {$A+}), fields in record types that are declared without the packed modifier and fields in class structures are aligned on quad word boundaries. Regardless of the state of the $A directive, variables and typed constants are always aligned for optimal access. Execution is faster if you set the option to 8 (Quad Word). 
    This is the default. 
     
      

  3.   

    要回答这个问题,就得了解编译器的对齐策略;对齐策略取决于体系架构,也就是说采取某种对齐策略必须得有意义。所以,先要了解为什么在 x86 架构上需要对齐,intel 手册 basic 卷中(4-2 vol 1):
    4.1.1  Alignment of Words, Doublewords, Quadwords, and Double Quadwords
    Words, doublewords, and quadwords do not need to be aligned in memory on natural boundaries. The natural boundaries for words, double words, and quadwords are even-numbered addresses, addresses evenly divisible by four, and addresses evenly divisible by eight, respectively. However, to improve the performance of programs, data structures (especially stacks) should be aligned on natural boundaries whenever possible. The reason for this is that the processor requires two memory accesses to make an unaligned memory access; aligned accesses require only one memory access. A word or doubleword operand that crosses a 4-byte boundary or a quadword operand that crosses an 8-byte boundary is considered unaligned and requires two separate memory bus cycles for access.所以默认的对齐策略是:结构中的每一个成员,都能够对应到相应的 natural boundary。
    v2 宽度是10字节,它的 natural boundary 是被8整除(因为 x86 通用寄存器和 x87 浮点寄存器不需要更大的对齐数)。在 v2 之后也要有额外的用于对齐字节的原因是:如果不保留额外的空间,当使用该结构体的数组时,将无法保证数组中每个该成员都能够对齐到 natural boundary。因此,它的结构是:
      00~00  b1
      01~01  b2
      02~03  2 bytes alignment
      04~07  ID
      08~17  v2
      18~23  6 bytes alignment由于 v1 的每个成员都是1字节,实际上是不需要为 v1 作出任何调整的,哪怕它的偏移量是奇数;但该结构中最大的 natural boundary 是4(ID),所以整个结构体会增加额外的字节,以保证即使在该结构的数组中,ID 仍然是对齐的:
      00~00  b1
      01~01  b2
      02~03  2 bytes alignment
      04~07  ID
      08~17  v1
      18~19  2 bytes alignment
      

  4.   

    这样理解先看四个重要的基本概念:
    1.数据类型自身的对齐值:
      对于char型数据,其自身对齐值为1,byte型为1,int为4,Extended为10,单位字节。
    2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
    3.指定对齐值:delphi编译器中配置的值,一般为1,2,4,8。
    4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。知道了上面四个概念
    假设delphi编译器指定的值为8
    来分析T1和T2
    对于T1:
    T1 = record
      b1,b2:Boolean;
      ID:Integer;
      v2:Extended; // 10
    end;首先b1自身对齐值1,指定值8,有效值为1,存在第1个位置
        b1自身对齐值1,指定值8,有效值为1,存在第2个位置
        ID自身对齐值4,指定值8,有效值为4,存在第5-8的位置(4的倍数)
        v2自身对齐值10,指定值8,有效值为8,存在第9-18的位置
    结束,再看整个结构体T1的自身对齐值为其中最大的值为10,指定值8,有效值为8,所以要根据8的整数倍进行圆整,我们已经存了18个,其后补6个字节进行圆整即变为24个字节。对于T2:
    T2 = record
      b1,b2:Boolean;
      ID:Integer;
      v1:array [0..9] of Byte; // 10
    end;首先b1自身对齐值1,指定值8,有效值为1,存在第1个位置
        b1自身对齐值1,指定值8,有效值为1,存在第2个位置
        ID自身对齐值4,指定值8,有效值为4,存在第5-8的位置(4的倍数)
        v1按10个byte存,自身对齐值为1,指定值8,有效值为1,存在第9-18的位置
    结束,再看整个结构体T2的自身对齐值为其中最大的值为4,指定值8,有效值为4,所以要根据4的整数倍进行圆整,我们已经存了18个,其后补2个字节进行圆整即变为20个字节。结果
    T1:
    1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24
    b1 b2       id id id id v2 v2  v2  v2  v2  v2  v2  v2  v2  v2  T2:
    1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20
    b1 b2       id id id id v1 v1  v1  v1  v1  v1  v1  v1  v1  v1 
    其实按照这样的结构体进行对比看更容易
    T1 = record
      b1:Boolean;
      ID:Integer;
      b2:Boolean;
    end;T2 = record
      ID:Integer;
      b1:Boolean; 
      b2:Boolean;
    end;域中只是顺序变化了下
    然而sizeof(t1)=12;sizeof(t2)=8
      

  5.   

    这种对齐问题在不同编译器下是不同的,但是可以加上Packed来保证按一字节对齐。
      

  6.   

    终于知道为啥那么多人总爱瞎加 packed 了,你倒是找一个21世纪出现的、默认会使用不同策略的 win 平台编译器出来?
      

  7.   

      T1 = record
        v2:Extended; // 10
        b1,b2:Boolean;
        ID:Integer;
      end;按 yqdragon(小布点) 点的理论这个就是16 。 确实不错
      

  8.   

    多谢各位指点。受益匪浅。
    #9 说的编译器,我想应该是 Project / Options / Complier / record field alignment
    不瞒大家,我在写字段解析的代码。
    就是可以根据 delphi 的声明文字,得到某个文件里的一条条记录。
    先就这样,继续研究。