struct的定义:
struct 结构标签
{
类型1 标识符1;
类型2 标识符2;
类型3 标识符3;
类型4 标识符4;
类型5 标识符5;
};
0.建议将struct的声明和变量的定义分开写
1.struct内可以放任何类型的变量声明;
3.struct的内部默认为public
struct的内存对齐:
对齐原则:
0.数据成员对齐规则。每个数据成员存储的起始位置要从该成员大小的整数倍开始。
1.数据成员包含结构体:结构体成员要从其内部最大元素大小的整数倍地址开始存储。
2.结构体的总大小:是其内部最大基本成员的整数倍,不足的要补齐。
struct A{
int a;
double b;
float c;
};
struct B{
char e[2];
int f;
double g;
short h;
struct A i;
};
sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。
sizeof(B) = 48; 看看B的内存布局。
e f g h i
B的内存布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * *
i其实就是A的内存布局。i的起始位置要为24的倍数,所以h后面要补齐。
如果定义了#pragma pack(8)
对齐原则:
0.数据成员对齐规则。每个数据成员存储的起始位置要从min(sizeof(该数据成员类型),8)的整数倍地址开始。
1.数据成员包含结构体:结构体成员要从其内部min(sizeof(子结构体中数据成员最大的类型),8)的整数倍地址开始存储。
2.结构体的总大小:是min(8,sizeof(内部最大基本成员)的整数倍,不足的要补齐。
位域对齐,找到以下资料:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
关于内存对齐的优点及必要性: Data alignment: Straighten up and fly right
参数传递:
0.一个int类型的参数i与一个只含有一个int类型的结构体s参数传递时,可能大不相同。i可能被传入到寄存器而s则压入堆栈。
1.可以定义一个只包含数组的结构体,通过结构体的赋值实现数组的copy。
union的定义:
union 联合标签
{
类型1 标识符1;
类型2 标识符2;
类型3 标识符3;
类型4 标识符4;
类型5 标识符5;
};
联合体与结构体的区别:
0.结构体中,每个变量依次存储。
1.联合体中,每个变量都是从偏移地址零开始存储,每次只有一个成员存储于该地址。
联合体可以把统一数据解释为不同的东西,例如:
union bits32_tag
{
int int_value;
struct { char c0,c1,c2,c3;}char_value;
};
union bits32_tag tt;
tt.int_value = 0xa0b0c0d;
则
tt.char_value.c0=0xd;
tt.char_value.c1=0xc;
tt.char_value.c2=0xb;
tt.char_value.c3=0xa;
分别为int _value的8个字节。
enum的定义:
enum 枚举标签{small, media =7, large =10,humungous};
0.枚举通过简单的操作将一串名字和一串整型值相联系起来。
1.缺省情况下,枚举从零开始,如果对列表中的某一个标识符赋值,下一个标识符值比前面一个的值大1.
2.#define 定义的值在编译时候消失,但是枚举定义的,则在调试的过程任然是可见的,可以在代码调试中使用它们。