(一)结构体
1.结构体的定义
结构体是一些值的集合,而这些值是结构体的成员变量,当然了结构体内的成员可以是不同类型的变量
2.结构体的声明
先来看一个例子:
struct tag
{
menmber_list;
}variable-list
在这个结构体中,tag是一个标签,而member-list是结构体的成员变量,那么variable-list是结构体定义的变量·
在这三者之中,tag标签虽然可以省略,但是当你使用结构体定义的变量时会发现不知是哪个,会带来不便,所以不建议省略;
member-list是结构体成员,肯定不能省略;
variable-list是结构体定义的变量,可以进行省略。
注:特殊的声明
例如:
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20],*p;
上面的这两个结构体在进行声明的时候省略掉了标签,当进行 p = &x时,编译器会发出警告。把上面两个声明当成完全不同的两个类型是非法的
所以我们在进行结构体声明的时候建议最好不要省略结构体标签
3.结构体变量的定义和初始化
struct Stu
{
int x;
int y;
int c;
}r1;//声明变量的同时也同时定义了变量r1
struct Stu r2; //定义结构体变量r2
struct Stu r3 = {x,y,c};//初始化:定义变量的同时赋初值
在这里我们需要注意的是: 数组可以整体初始化,但是禁止整体赋值,可以单个元素赋初值
那么结构体和数组相似,可以整体赋予初值,但是不允许整体赋值
char arr[10] = {0};//整体赋初值即进行初始化
int arr[20] = {1,2,3,4,6,7,9,0,5,5,6};//整体赋初值即进行初始化
a = 20;//禁止整体赋值
a[5] = 3; //可以单个赋值
4.结构体内存对齐问题
先来看一段代码:
struct S1
{
char c1;
int i;
char c2;
};
int main()
{
printf("%d\n",sizeof(struct S1));
return 0;
}
按照我们自己的算法结构体大小应该是6,但是结果真的是这样的吗?
可以看到结果和我们想象中的并不一样,于是结构体是存在内存对齐的,我这里的编译器默认的值为8
测试环境VS2008,Win 10
结构体对齐规则:
(1) : 第一个成员在结构体变量偏移量为零的地址处
(2) : 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数=8和该成员大小的较小值,当然了Linux默认的值为4
(3) : 结构体大小为最大对齐数的整数倍
(4) : 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
来看例子(不含嵌套结构体的情况)
struct S3
{
double d;
char c;
int i;
};
int main()
{
printf("%d\n",sizeof(struct S3));
return 0;
}
double含有8个字节,从0开始对齐,一直到8,然后char是一个字节,从8开始对齐往后一个字节,那么到int的时候,9不是对齐数,往后偏移3个到12,12再加上int的4个字节,最后对齐的为16,而16正好是8的整数倍,所以结构体大小为16
(含嵌套结构体的情况)
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%d\n",sizeof(struct S4));
return 0;
}
char类型为1个字节,struct S3为16个字节,1和8中间差了7,所以1+7对齐到8,然后8加上16到24,24再加上double的8个字节到32,32是8的整数倍,所以结构体大小为32
(二)位段
位段 的声明和结构体类似,但是位段的成员必须是int ,unsigned int,signed int
位段的成员名后边有一个冒号和数字
struct A //A就是一个位段类型
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
A的大小为8个字节
可以看出位段比结构体要节省空间,但是有跨平台的问题存在
(三)枚举和联合
枚举就是把可能的取值一一列举,枚举不存在内存对齐问题
enum Day
{
Mon, //枚举常量,默认从零开始,依次递增1,当然了我们自己也可以进行赋初值
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex
{
MALE,
FEMALE,
SECRET,
};
以上定义的enum Day,enum Sex都是枚举类型
联合
联合又称为共用体,联合也存在内存对齐问题,联合的成员共用同一块内存空间,所以联合至少得有能力存储最大的成员
union Un
{
int i;
char c;
};
union Un un;
int main()
{
printf("%d\n",&(un.i));
printf("%d\n",&(un.c));
return 0;
}
两个输出的结果是一样的
union Un
{
int i;
char c;
};
union Un un;
int main()
{
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n",un.i);
return 0;
}
因为i和c公用同一块内存空间,所以第一个字节里存的是c的内容,剩下的字节里是i的内容
内存对齐问题:
先来看一段代码:
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
int main()
{
printf("%d\n",sizeof(union Un1));
printf("%d\n",sizeof(union Un2));
return 0;
}
结果为:
计算方法为:(1)联合的大小至少是最大成员的大小
(2)当最大成员大小不再是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍
union Un1中 char c[5]占了5个字节,所以int 对齐数为8
union Un2中 short c[7]占了14个字节,所以int对齐数为16
当然了利用联合还可以判断计算机的大小端存储问题