自定义类型:结构体(字节对齐)、枚举、联合

结构体定义定义结构体变量

struct Test
{
	char a;
	double b;
	int c;
}t, *pt, tar[10];

void main()
{
	struct Test t;
	struct Test *pt;
	struct Test tar[10];
}

匿名结构体—定义结构体同时定义结构体变量:

struct
{
	char a;
	double b;
	int c;
}t;

void main()
{
	t.a = 's';
	t.b = 3.14;
	printf("%c\n", t.a);
	printf("%f\n", t.b);
}

上述代码结果:
在这里插入图片描述
结构体自引用

typedef struct Node
{
	int data;
	struct Node *next;
}Node;

结构体变量的定义和初始化

typedef struct Student
{
	char name[10]; //falfkafklaflaasi
	int age;
}Student;

void main()
{
	Student s = {"abc", 10};
	Student s1;
	strcpy(s1.name, "xyz"); //memcpy
}

结构体内存对齐:
先介绍一下结构体的对齐规则
1.第一个成员在与结构体变量偏移量为0的地址处;
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有对齐数(含嵌套结构体的对齐数)的整数倍。
5.VS中默认的对齐数为8。
下面列举一些例子,过程见注释:
例1:

typedef struct Test
{
	char a;   //1 + 7
	double b; //8
	int c;    //4 + 4
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
	Test t;
	t.a = 'A';
	t.b = 12.34;
	t.c = 100;
}

结果为:
在这里插入图片描述
例2:

typedef struct Test
{
	char a;   //1 + 3
	int c;    //4 
	double b; //8
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
例3:

#pragma pack(2)
typedef struct Test
{
	char a;   //1 + 1
	double b; //8
	int c;    //4 
}Test;
void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
例4:

#pragma pack(1)
typedef struct Test
{
	char a;   //1 + 1
	short b;  //2
	int c;    //4 
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
注:如果设置对齐数为1,则直接将所有变量所占的字节数相加即可。

例5:

typedef struct Test
{
	short a;    //2 + 6
	struct
	{
		int b;    //4 + 4
		double c; //8
		char d;   //1 + 7
	};
	int e; //4 + 4
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
注:最后一个变量仍然要凑够8个字节;

例6:

#pragma pack(2)
typedef struct Test
{
	int a; //4
	struct
	{
		double b[10]; //80
		int c;        //4
		char d;       //1 + 1
	};
	int e;//4
}Test;

结果为:
在这里插入图片描述
例7:

#pragma pack(4)
struct S4
{
	char c1;  //1 + 3
	
	struct
	{
		double d; //8
		char c;   //1 +3
		int i;    //4
	};
	double e; //8
};

void main()
{
	printf("%d\n", sizeof(struct S4));
}

在这里插入图片描述
例8:

#pragma pack(16)
struct S4
{
	char c1;  //1 + 7
	
	struct
	{
		double d; //8
		char c;   //1 +3
		int i;    //4
	};
	double e; //8
};

void main()
{
	printf("%d\n", sizeof(struct S4));
}

结果为:
在这里插入图片描述
注:16和8选择最小值8。

例9:

#pragma pack(16)
struct S3
{
	double d; //8
	char c;   //1 +3
	int i;    //4
};

struct S4
{
	char c1;  //1 + 7
	struct S3 s3; //16
	struct 
	{
		double d; //8
		char c;   //1 +3
		int i;    //4
	};
	double e; //8
};

void main()
{
	printf("%d\n", sizeof(struct S4));
}

结果为:
在这里插入图片描述
例10:

#pragma pack(4)
struct S3
{
	double d; //8
	char c;   //1 +3
	int i;    //4
};

struct S4
{
	char c1;  //1 + 3
	struct S3 s3; //16
	struct 
	{
		double d; //8
		char c;   //1 +3
		int i;    //4
	};
	double e; //8
};

void main()
{
	printf("%d\n", sizeof(struct S4));
}

结果为:
在这里插入图片描述
例11(关于位域)

typedef struct Test
{
	char a : 1;  //位域 位段  占八位中的一位
	char b : 1;//和上面的元素占同一个字节
	char c : 1;
}Test;

void main()
{
 printf("%d\n", sizeof(Test));//一共占了一个字节其中的三位
}

结果为:
在这里插入图片描述
例12:

typedef struct Test
{
	char a : 2;  //位域 位段 
	char b : 3;
	char c : 4;
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
例13:

//基本数据类型的自身对齐值:
//自定义类型的自身对齐值:
//程序的指定对齐值:
//程序的有效对齐值:

//位域不能跨字节存储
//位域不能跨类型存储
typedef struct Test
{
	char a : 1;
	int  b : 1;
}Test;

void main()
{
	printf("%d\n", sizeof(Test));
}

结果为:
在这里插入图片描述
注意:位域不能跨字节存储,位域也不能跨类型存储

枚举类型:
例如:

enum Day//星期
{
	Mon = -100,
	Tues,
	Wed,
	Thur = 100,
	Fri,
	Sat,
	Sun
};

void main()
{
	enum Day d = Mon;
	printf("%d\n", Tues);//从有值的元素开始递增
	printf("%d", Fri);//碰到下一个被赋值的元素,以该元素为起点,继续递增。
}

结果为:
在这里插入图片描述
联合(共同体)
这种类型定义的变量也包含一系列的成员,这些成员公用同一块空间(所以联合也叫共用体)
联合的特点:
1、一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍(最后一个例子)。
例1

union Un
{
	int i;
	char c;
};

void main()
{
	union Un un;

	printf("%p\n", &(un.i));
	printf("%p\n", &(un.c));

	//下面输出的结果是什么?
	un.i = 0x11223344;  //44 33 22 11
	un.c = 0x55;        //55 33 22 11
	printf("%x\n", un.i);
}

结果为:
在这里插入图片描述
例2(判断大小端)

bool check_modle()
{
	int a = 0x01; //00 00 00 01
	return *(char*)&a == 0x01;
}
void main()
{
	if(check_modle())
		printf("小端.\n");
	else
		printf("大端.\n");
}

结果为:
在这里插入图片描述
例3(用联合体判断大小端):

bool check_modle()
{
	union
	{
		int a;
		char c;
	}un;
	un.a = 0x01;
	return un.c == 0x01;
}
void main()
{
	if(check_modle())
		printf("小端.\n");
	else
		printf("大端.\n");
}

结果为:
在这里插入图片描述
例4:

union Un1
{
	char c[5]; //5
	int i;     //4
};
union Un2
{
	short c[7];
	int i;
};
void main()
{
	printf("%d\n", sizeof(union Un1));//8
	printf("%d\n", sizeof(union Un2));//16
}

结果为:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值