结构体
1.结构体的自引用
struct Node
{
int data;
struct Node next;
};
这样在结构中包含一个类型为该结构本身的成员是否可以呢?
不可以
正确的自引用方式为:
struct Node
{
int datd;
struct Node *next;
};
2.结构体内存对齐
为什么存在内存对齐?
大部分的参考资料都是如是说的:
- 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能
在某些地址处取某些特定类型的数据,否则抛出硬件异常。 - 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的
内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。
对齐原则 - 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8 - 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
总结对齐规则为
(1)基本数据类型有一个对齐值。
(2)自定义类型有一个对齐值(如结构体类型),对齐值是成员中字节最大 的值。
(3)程序指定对齐值(指定方式为**#pragma pack()**)。
(4)程序有效对齐值。
重点是(3)和(4),内存对齐要按照两者中字节较小的方式对齐。
例题1
#pragma pack(2)
typedef struct Test
{
char a;//1
char b;//1
char c;//1
}Test;
sizeof(Test)=3,并不是6,虽然程序指定对齐为2,但有效对齐值为1,比2小,因此要按1对齐,所以sizeof(Test)=1+1+1=3。
例题2
struct S1
{
char a;//1
double b;//8
int c;//4
};
求sizeof(struct S1)
首先数据类型本身有一个对齐值,如上所示,最大对齐数为8,则
(1)最大的内存字节上面的数据内存对齐值的和要为8的整数倍。
(2)其次结构体总大小是最大内存对齐数8的整数倍。
首先看第一条
struct S1
{
char a;//1+7
double b;//8
int c;//4
};
由第一条可得char a;后面的1字节要加7和最大内存对齐数8对齐,此时结构体总大小为8+8+4=20,但并不是最大内存对齐数8的整数倍,因此int c所占的4个字节要加4,从而为最大内存对齐数的整数倍。
struct S1
{
char a;//1+7
double b;//8
int c;//4+4
};
sizeof(struct S1)=24。
例题3
struct S2
{
char a;//1
int c;//4
double b;//8
};
求sizeof(struct S2)
(1)首先int c占4个字节,上面的数据类型要加3;
(2)结构体总大小为最大内存对齐数8的整数倍。
struct S2
{
char a;//1+3
int c;//4
double b;//8
};
此时sizeof(struct S1)=16,正好是8的整数倍。
例题4
typedef struct Test
{
short a;//2
struct
{
int b;//4
double c;//8
char d;//1
};
int e;//4
}Test;
这是一个结体嵌套,要首先看内部结构体
typedef struct Test
{
short a;//2
struct
{
int b;//4+4
double c;//8
char d;//1+7
};
int e;//4
}Test;
需要注意的是,内部结构体总字节大小为24,但short a一定不能按24对齐,而是按照结构体本身的类型对齐,即结构体成员中的最大字节数8对齐。即
typedef struct Test
{
short a;//2+6
struct {};//8
int e;//4
}Test;
这样看问题就容易得多了,此时总字节大小为8+24+4=36,不是8的倍数,因此有
typedef struct Test
{
short a;//2+6
struct{ };//8
int e;//4+4
}Test;
总大小为8+24+8=40;
例题5
typedef struct Test
{
short a;//2
struct
{
int b;//4
double c[10];//80
char d;//1
};
int e;//4
}Test;
求sizeof( Test)
先看内部,同样int b不能按80对齐,而是按照double 本身的字节大小8对齐
即
struct
{
int b;//4+4
double c[10];//80
char d;//1
};
此时内部大小为89,不是最大内存8的倍数,则有
struct
{
int b;//4+4
double c[10];//80
char d;//1+7
};
再看整个程序
typedef struct Test
{
short a;//2+6
struct{ };//8(96)
int e;//4
}Test;
此时总字节大小为108,不是8的倍数,则
typedef struct Test
{
short a;//2+6
struct{ };//8(96)
int e;//4+4
}Test;
sizeof(Test)=8+96+8=112。
例题6
#pragma pack(4)
struct tagAAAA
{
struct
{
char ucFirst; //1 + 1
short usSecond; //2
char ucThird; //1 + 1
}half;
short kk; //2
}number;
//8
//虽然设置的内存对齐数为4,但要按照结构体成员最大的字节2对齐,即按(3)和(4)较小的字节对齐
struct tagBBBB
{
char ucFirst; //1 + 1
short usSecond; //2
char ucThird; //1 + 1
short usForth; //2
}half;
//8
struct tagCCCC
{
struct
{
char ucFirst; //1 + 1
short usSecond; //2
char ucThird; //1 +1
}half;
long kk; //4 + 2
};
//12