打印

C语言字节对齐

[复制链接]
1036|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
C语言字节对齐
更多资料请访问我的博客blog.sina.com.cn/ifreecoding

太长了,发不了这么长,请下载PDF文档阅读
C语言字节对齐.pdf (262.64 KB)

字节对齐的由来
程序在运行时会将数据临时存放在内存中,芯片内核需要对这些数据进行计算,不断的读取内存以获得数据,并将计算结果写入内存。计算机体系经过若干年的发展,最终确定了以8bits作为其基本的存储单元——byte(字节),这是每个地址所对应的最小访问单元,在C语言中对应一个char型的变量。
下图为芯片内核访问内存的示意图。芯片内核通过控制总线控制内存的动作,通过地址总线告知内存地址,数据总线上出现交互的数据。

1  访问内存示意图
假设上图是8位机的示意图,那么数据总线的宽度是8bits,由8根数据线组成,这样芯片内核与内存之间一次就可以同时交换8bits的数据,正好是一个字节。图中右侧的每个小格子代表一个存储地址,对应一个字节。
下面通过一段C语言代码来具体看看芯片内核与内存之间的数据交互过程。
char data[2];
data[0] = 2;
data[1] = data[0] + 1;
第一行代码定义了2个字节的数组data。假设data数组被编译到地址0x100,那么data[0]这个字节就被存储在地址为0x100的内存空间,data[1]这个字节就被存储在地址为0x101的内存空间。
第二行对应的硬件动作是将数据2存入到data[0]中,也就是将数据2存入到内存中的0x100地址,执行这条语句时,芯片内核对控制总线、地址总线和数据总线进行操作,控制总线上出现写信号,地址总线上出现数据0x100,数据总线上出现数据0x02。此时内存就知道需要将数据2写入到地址0x100中,完成一次写操作。
第三行先读出data[0]中的数据,芯片内核将控制总线置为读信号,将地址总线置为0x100,此时,内存就会从其内部取出0x100地址中的数据,也就是数据22将出现在数据总线上,此时芯片内核就会通过数据总线读取到data[0]中的数据了。接下来芯片内核计算2+1=3,需要将数字3写入到data[1]中,芯片内核将控制总线置为写信号,将地址总线置为0x101,将数据总线置为3,内存接收到这些信号后,就会将数据3存入到其内部0x101地址中,完成本次操作。
从上述介绍的过程可以看出,芯片内核与存储芯片之间每次操作可以传递1个字节的数据,如果要传递多个字节的数据就需要重复这个过程,这受限于数据总线的宽度。
计算机技术在不断的发展,在8bits数据总线之后又相继出现了16bits32bits乃至64bits数据总线,它们分别对应于我们所谓的8位机、16位机、32位机以及64位机。对于16位机一次可以交互2个字节的数据,32位机一次可以交互4个字节的数据,64位机一次可以交互8个字节的数据,可以看出总线的带宽增加了,速度成倍提高。
32位机为例,我们在访问0地址时,可以一次访问4个字节的数据,这4个字节的数据占用了4个内存地址,也就是说访问0地址时同时可以访问01234个地址,访问4地址时可以同时访问45674个地址。我们不难得出这样的结论:在地址总线上只要出一个地址,就可以连同访问这个地址及其后面的3个地址中的数据,这4个地址正好可以组成一个32bits的数据,通过访问数据总线一次即可获得,而对这个地址的要求就是:需要4字节对齐(对于64位机则需要8字节对齐)。在芯片设计时遵循了这个要求,地址总线上只需要出现048……这样4的整数倍的地址就可以同时访问连续4个字节的内存空间,这就是字节对齐的根源——是由硬件决定的!为了配合硬件的4字节对齐访问,软件的编译器链接器也对软件做了限制,需要4字节对齐访问。
有关计算机的设计五花八门,上述有关控制总线、地址总线、数据总线的介绍只是原理性的介绍,不同芯片在具体实现时会有所不同。
字节对齐规则
我们在写代码时一般并不会指定变量存放在内存中的地址,这是由编译器链接器决定的,而编译器链接器则遵循了4字节对齐的原则,以32位机为例,其规则是1字节长度的变量可以被编译链接到任何地址,2字节长度类型的变量被编译链接到2的整数倍的地址,4字节长度类型的变量被编译链接到4的整数倍的地址。因此,取signed/unsigned char类型变量的地址,它可以是任意地址。取signed/unsigned short int类型变量的地址,它一定是2的整数倍。取signed/unsigned intsigned/unsigned long类型变量的地址,它一定是4的整数倍。
C语言的结构体类型由多种基本类型组成,比较利于讨论字节对齐的问题,下面我们将以结构体为例讲解字节对齐规则。以下例子除特殊说明外,均是在X86 32CPUVC2010环境下测试。
1
typedef struct example1
{
    char a;
}EXAMPLE1;
结构体EXAMPLE1比较简单,它其实就是一个char型,它的长度sizeof(EXAMPLE1)1
2
typedef struct example2
{
    char a;
    short b;
}EXAMPLE2;
结构体EXAMPLE2中包含了2个变量,其中chara的长度为1shortb的长度为2,但结构体EXAMPLE2的整体长度sizeof(EXAMPLE2)却为4,而不是1+2=3,这种现象就是字节对齐造成的。
为了方便观察结构体中变量相对结构体头的偏移地址,我们定义如下的宏:
#define OFFSET(s, e)

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

68

帖子

3

粉丝