程序的机器级表示:特殊数据结构(续)
结构(Structures)
结构的表示
在C语言中,结构用struct定义,例如:
struct rec {
int a[4];
size_t i;
struct rec *next;
};
表示定义了一个结构体rec,其中包含了成员int数组、占8字节的size_t类型和指针
结构占用的是一块空间,这块空间足以放下所有的成员
结构的对齐
按平常的理解,结构中的成员在地址上应该是连续的、紧密相接排列的。例如:
struct S1 {
char c;
int i[2];
double v;
} *p;
紧密相接时,在地址上应该是这样排列的:
但这样的排列不利于底层对数据的读取,因此实际上是进行了对齐处理的:
对齐规则:
占用N字节的类型所在的地址必须被N整除
例如,在上述结构S1中,char类型占1个字节,p(p是8的整数倍)可以被1整除,因此可以直接存储在首位。接下来考虑int型的数组,因为int类型占4个字节,所以地址应该是4的倍数,因此从p+4的地方开始存储,存两个元素,存到p+12前。而double类型占8个字节,因此需要从p+16(能够被8整除)处开始存储,存到p+24前
为结构分配的长度(字节数),也必须是占用空间最大的成员类型所占用的字节数K的整数倍。因此,有时候在最后一个成员存储结束后,还需要再分配一些空间凑到K的整数倍(尽管在这些空间上不进行存储)
例如,下述结构:
struct S3 {
short i;
float v;
short j;
} a[10];
最大的类型为float,占用4个字节。因此每一个S3结构占用的长度都应该是4的整数倍,在此处每一个S3结构占用的大小为12字节:
同时注意到,结构数组其实就是结构按顺序排列,在地址上是连续的
如此设计的原因:地址不可能一个挨着一个计算,如此设计可以使得在读写结构中每一个变量的值时,底层计算地址很方便
对齐的作用:防止跨页现象
32位机:4字节对齐
64位机:8字节对齐
根据上述的存储原理,在定义结构时,成员的先后顺序会影响为结构分配的空间大小,例如:
// S4
struct S4 {
char c;
int i;
char d;
} *p;
// S5
struct S5 {
int i;
char c;
char d;
} *p;
结构S4占用12字节,而结构S5则只占用了8字节。注意到将占用字节大的类型放在前面会更省存储空间
联合(Union)
联合(共用体)只给最大的元素分配空间,例如:
union U1 {
char c;
int i[2];
double v;
} *up;
只分配8个字节(double型占用8个字节,是占用的最多的):
共用体任何时候只能有一个成员带有值