自定义类型
一.结构体
当对象信息内容包含多种数据类型时,我们可以使用结构体来进行自定义数据类型。
如:学生的信息包含姓名、学号、性别、身份证号以及电话号码等。 可以创建结构体。
1.结构体(变量)的定义:
格式1:
格式2:
注意:以上两种方式定义的结构体变量均为全局变量。但是若将格式2的语句写在某一个函数内部,此时的结构体变量则为局部变量。
2.结构体的初始化
格式:
struct student
{
char name[1024]; //结构体的成员
char class_num[1024];
char sex[1024];
}stu1 = { "张三",18203809,"男" }; //在定义结构体时定义结构体变量并且初始化
struct student stu2 = { "张三三",17020908,"男" };//定义结构体变量并初始化
同样地,上述均是全局变量,但是当第二条语句是在某个函数内部写的时候,则是局部变量。
3.结构体的内存对齐(结构体的大小)
结构体的大小并不是进行内部成员变量的加和。
1.内存对齐的规则:
简言之如下
①结构体第一个成员与结构体变量的地址相同。
②其他成员变量都要对齐到对齐数的整数倍的地址处
③对齐数=Min(编译器默认的对齐数,该成员大小)取最小值。(VS默认值为8,Linux默认值为4)
每个成员变量均有一个对齐数。
④结构体总大小为最大对齐数的整数倍。
⑤结构体内有嵌套的结构体时,则其最大对齐数就是嵌套的结构体的大小。
举例:
struct stu
{
int a;
double b;
short c;
};
printf("%d\n", sizeof(struct stu)); //24 最大对齐数为8,short要对齐到8,
//又因为必须是最大对齐数的整数倍,所以是24.
2.那么问题来了,对齐数可以修改吗。答案是可以的。这里需要用到预处理指令。如下:
#pragma pack(4)
int main()
{
struct stu
{
int a;
double b;
short c;
};
printf("%d\n", sizeof(struct stu)); //16 最大对齐数为8,short对齐到4即可.
3.为了让结构体尽可能地小,我们可以将占空间小的成员变量集中在一起。
如:
形式1:
struct stu
{
char a;
int b;
char c;
};
printf("%d\n", sizeof(struct stu)); //12 最后一个成员变量由于内存对齐需要对齐到4,
//并且最后结果要是最大对齐数的整数倍,故为12
形式2:
struct stu
{
char a;
char c;
int b;
};
printf("%d\n", sizeof(struct stu)); //8 节省空间
显然,形式2比形式1节省空间,当结构体成员变量较多时,形式2的代码则会更有效率。
注意:结构体内成员变量的声明顺序就是在内存中的存储顺序。
例:
由此就可以清晰地看到结构体变量第一个成员变量的地址与结构体变量的地址是相同的,先声明的变量地址靠前。
4.位段
在这里,小编将它理解为与结构体一模不一样,位段是描述成员占了几个比特位。
话不多说,上代码:
例如:
struct stu
{
int a : 2;//成员名后加冒号,冒号后是该变量占了几个比特位
int b : 4;
int c : 6;
}s1;
printf("%d\n",sizeof(struct stu));
1.
2.
3.
由于unsigned 一个存储单元是4B,所以当位段和不超过32bit时,都存在同意个存储单元中,但是,当超过了32bit时,就得存储在新的存储单元上了,
一个变量只能存储在同一个存储单元上。
4.
29>8,超过了char的存储单元大小,所以时错误的写法。
我们可以看到位段的特点:
1.声明与结构体类似
2.成员变量名后有冒号,冒号后面有数字。而这个数字就表明该成员变量占几个比特位。
注意:位段的成员必须是int、unsigned int、signed int或者char。
位段可以使用%d,%u,%x,%o输出。
二.枚举
枚举类型的定义:
enum Day
{
Mon, //枚举常量从0开始
Tue,
Wed
}day;
day = Mon; //只能用枚举常量位枚举变量赋值
printf("%d\n", day);
从中可以看到:
1.枚举常量的列举之间用逗号分隔开。
2.只能用枚举常量位枚举变量赋值。
3.默认枚举常量从0开始。
三.联合体
何为联合体,小编的理解就是,一系列成员共用同一块内存空间。联合体的大小至少得是其中最大成员的大小,当其中的最大成员的大小不是最大对齐数的整数倍时,对齐到最大对齐数的整数倍。
上代码:
明显的看到联合体的成员是共用着同一块内存空间的。
联合体的用处:
1.判断计算机的大小端存储
先来了解什么是大小端存储,
小端:对一整数,其低位在计算机中的高地址上存储。
大端刚好相反。
明显看到,修改了的是低地址,如果是大端,结果应为55223344,所以计算机是小端存储。
2.IP地址转换(十进制转点分十进制)
ip地址就是32位的整数将它用联合体转换位点分十进制。
union ip
{
uint32_t num;
struct
{
char dec1;
char dec2;
char dec3;
char dec4;
};
}IP;
IP.num = 0x11223344;
printf("%d.%d.%d.%d\n", IP.dec1, IP.dec2, IP.dec3, IP.dec4 );
注意:使用uint32_t需要包含的头文件是#include<stdint.h>.
总结:
结构体:
1.当对象所包含的信息有多种数据类型时,我们可以采用结构体处理。
2.结构体的大小不仅与操作系统有关,还和编译器的默认对齐数有关。
3.为了使代码高效,姐合适呢个内存空间,我们可以将成员小的变量尽量放在一起。
4.当结构体需要作为函数参数时,结构体指针是最佳选择。
枚举:
对对象的简单列举
联合体:
只需注意其中的成员是公用一块内存空间。