字节对齐问题

iamduo 2011-07-18 01:09:46
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) = 10

SizeOf(T1) = 24 ?????
SizeOf(T2) = 20

可以将以上两个结构写入文件中用 UltraEdit 看。
T1 中最后多出了4个字节,我无法理解。
我一直以后,是4字节一分配。
够的话,接在后面,
不够的时候,再开4字节。

哪位高手能解释,为什么两个结构体,得到的大小不一样。
(Delphi2007 + WinXP)
...全文
234 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
iamduo 2011-07-30
  • 打赏
  • 举报
回复
多谢各位指点。受益匪浅。
#9 说的编译器,我想应该是 Project / Options / Complier / record field alignment
不瞒大家,我在写字段解析的代码。
就是可以根据 delphi 的声明文字,得到某个文件里的一条条记录。
先就这样,继续研究。
ynquan 2011-07-22
  • 打赏
  • 举报
回复
学习学习
Seamour 2011-07-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 sqldebug_fan 的回复:]
这种对齐问题在不同编译器下是不同的,但是可以加上Packed来保证按一字节对齐。
[/Quote]
终于知道为啥那么多人总爱瞎加 packed 了,你倒是找一个21世纪出现的、默认会使用不同策略的 win 平台编译器出来?
SQLDebug_Fan 2011-07-21
  • 打赏
  • 举报
回复
这种对齐问题在不同编译器下是不同的,但是可以加上Packed来保证按一字节对齐。
飞牛 2011-07-21
  • 打赏
  • 举报
回复
学习了
lyhoo163 2011-07-21
  • 打赏
  • 举报
回复
路过。
xhz2000 2011-07-21
  • 打赏
  • 举报
回复
T1 = record
v2:Extended; // 10
b1,b2:Boolean;
ID:Integer;
end;

按 yqdragon(小布点) 点的理论这个就是16 。 确实不错

rainychan2009 2011-07-21
  • 打赏
  • 举报
回复
根据对其规则而定,如果
第一个记录
按照1,2对其都是16
按照4就是20
按照8就是24
yqdragon 2011-07-18
  • 打赏
  • 举报
回复
这样理解

先看四个重要的基本概念:
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
浩南_哥 2011-07-18
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 seamour 的回复:]

要回答这个问题,就得了解编译器的对齐策略;对齐策略取决于体系架构,也就是说采取某种对齐策略必须得有意义。所以,先要了解为什么在 x86 架构上需要对齐,intel 手册 basic 卷中(4-2 vol 1):
4.1.1 Alignment of Words, Doublewords, Quadwords, and Double Quadwords
Words, doublewords,……
[/Quote]
学习了,刚开始还以为v2是从10~19呢。
Seamour 2011-07-18
  • 打赏
  • 举报
回复
要回答这个问题,就得了解编译器的对齐策略;对齐策略取决于体系架构,也就是说采取某种对齐策略必须得有意义。所以,先要了解为什么在 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
天涯倦客 2011-07-18
  • 打赏
  • 举报
回复
和编译开关 也有关系


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.
cngst 2011-07-18
  • 打赏
  • 举报
回复
Extended是按64位对齐的,所以它对齐后是16字节
DelphiTeacher 2011-07-18
  • 打赏
  • 举报
回复
packed record

16,749

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧