1、为了能使 CPU 对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的“对齐”。例如对于 4 字节的 int 类型变量,其起始地址应位于 4 字节边界上,即起始地址能够被 4 整除。变量的对齐规则如下(32 位系统):TypeAlignmentchar在字节边界上对齐short (16-bit)在双字节边界上对齐int and long (32-bit)在 4 字节边界上对齐float在 4 字节边界上对齐double在 8 字节边界上对齐structures单独考虑结构体的个成员,它们在不同的字节边界上对齐。其中最大的字节边界数就是该结构的字节边界数。MSDN 原话:Large
2、st alignment requirement of any member理解结构体的对齐方式有点挠头,如果结构体中有结构体成员,那么这是一个递归的过程。对齐方式影响结构体成员在结构体中的偏移设编译器设定的最大对齐字节边界数为 n,对于结构体中的某一成员 item,它相对于结构首地址的实际字节对齐数目 X 应该满足以下规则:X = min(n, sizeof(item)例如,对于结构体 struct char a; int b T;当位于 32 位系统,n=8 时:a 的偏移为 0,b 的偏移为 4,中间填充了 3 个字节, b 的 X 为 4;当位于 32 位系统,n=2 时:a 的偏移为
3、 0,b 的偏移为 2,中间填充了 1 个字节,b 的 X 为 2;结构体的 sizeof设结构体的最后一个成员为 LastItem,其相对于结构体首地址的偏移为 offset(LastItem),其大小为 sizeof(LastItem),结构体的字节对齐数为 N,则:结构体的 sizeof 为: 若 offset(LastItem) sizeof(LastItem)能够被 N 整除,那么就是 offset(LastItem) sizeof(LastItem),否则,在后面填充,直到能够被 N 整除。例如:32 位系统,n=8,结构体 struct char a; char b; T;str
4、uct char a; int b; T1;struct char a; int b; char c; T2;sizeof(T) = 2; N = 1 没有填充sizeof(T) = 8; N = 4 中间填充了 3 字节sizeof(T2)=12; N = 4 中间,结尾各填充了 3 字节注意:1) 对于空结构体,sizeof 1;因为必须保证结构体的每一个实例在内存中都有独一无二的地址。2) 结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与结构体的实例地址无关。例如:struct static int I; T; struct char a; static int I;
5、T1;sizeof(T) = 1; sizeof(T1) = 1;3) 某些编译器支持扩展指令设置变量或结构的对齐方式,如 VC,详见 MSDN(alignment of structures)以下为 Linux 内核代码中的例子:_attribute_(regparm(0) int printk(const char * fmt, .)_attribute_ (format (printf, 1, 2);禁止 printk 使用寄存器传递调用参数,并将 printk 的参数 1 作为 printf 格式串,从参数 2 开始检查其类型;void _switch_to(struct task_s
6、truct *prev, struct task_struct *next)_attribute_(regparm(3) ;_switch_to 保留 3 个寄存器用作传递参数;void _attribute_ (_section_ (“.text.init“) mem_init();将 mem_init 编绎到.text.init 段;struct tasklet_head tasklet_vec32 _attribute_(_aligned_(32),_section_(“.data.cacheline_aligned“) ;将 tasklet_vec32编绎到.data.cachelin
7、e_aligned 段,并将它在 32 字节边界上对齐;void do_exit(long error_code)_attribute_(noreturn);do_exit 不会返回;struct Xgt_desc_struct unsigned short size; unsigned longaddress _attribute_(packed);将 address 在结构中紧凑排列。-MSDN-#pragma pack(n)When you use #pragma pack(n), where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on the smaller member type or n-byte boundaries. If you use #pragma pack without an argument, structure members are packed to the value specified by /Zp. The default /Zp packing size is /Zp8.