自定义类型:结构体,位段,枚举,联合

目录

一、结构体

1、结构体类型的声明

2、匿名结构体类型:

3、结构体的自引用

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

5、结构体内存对齐

6、修改默认对齐数

二、位段

1、位段的声明

2、位段的内存分配

三、枚举

1、枚举类型的定义

2、枚举的优点

四、联合(公用体)

1、联合类型的定义

2、联合的特点

3、大小的计算


在C语言中我们知道有内置类型,如char,short,int ,float,double等,那么如果我们想用一个类型来表示一个复杂的对象该怎么办呢,这时候就要用到自定义类型。

一、结构体

1、结构体类型的声明

结构体是一些成员变量的集合,每个成员可以是不同类型的变量。

struct student
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
};

2、匿名结构体类型:

struct
{
	int a;
	char b;
	float c;
}x;

struct
{
	int a;
	char b;
	float c;
}a[20],*p;

 匿名结构体类型声明时,只能定义一次结构体全局变量。

另外,p=&x;不合法,因为编译器会把上面两个声明当成完全不同的两个类型。

3、结构体的自引用

struct Node
{
	int data;
	struct Node next;
};
//以上写法是错误的,在链表当中一个结包含成员变量的地址

应更正为:

struct Node
{
	int data;
	struct Node* next;
};
typedef struct
{
	int data;
	Node* next;
}Node;
//这样的写法是错误的

应更正为:

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

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

定义变量:

struct Point
{
	int x;
	int y;
}p1;//声明结构体类型的同时定义变量p1

struct Ponint p2;//定义变量p2

 定义变量并初始化:

struct Point
{
	int x;
	int y;
}p1={2,3};//声明结构体类型的同时定义变量p1并初始化

struct Point p2 = { 2,3 };//定义变量p2并初始化

结构体嵌套初始化:

struct Point
{
	int x;
	int y;
};
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1={10,{4,5},NULL};//声明结构体类型的同时定义变量n1并嵌套初始化

struct Node n2 = { 20,{5,6},NULL };//定义变量n2并嵌套初始化

5、结构体内存对齐

结构体的对齐规则:

a.第一个成员变量在偏移量为0的地址处

b.其他成员变量在偏移量为对齐数的整数倍处

(对齐数=编译器默认的对齐数与该成员大小的较小值)

c.结构体大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍

d.对于嵌套结构体情况:

嵌套的结构体对齐到自己的最大对齐数的整数倍处

结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

案例分析:

(1)

	struct S1
	{
		char c1;//对齐数为1
		int i;//对齐数为4
		char c2;//对齐数为1
	};
	printf("%d\n", sizeof(struct S1));

(2)

	struct S2
	{
		char c1;//对齐数为1
		char c2;//对齐数为1
		int i;//对齐数为4
	};
	printf("%d\n", sizeof(struct S2));

 

(3)

	struct S3
	{
		double d;//对齐数为8
		char c;//对齐数为1
		int i;//对齐数为4
	};
	printf("%d\n", sizeof(struct S3));

 

(4)

	struct S4
	{
		char c1;//对齐数为1
		struct S3 s3;//最大对齐数为8
		double d;//对齐数为8
	};
	printf("%d\n", sizeof(struct S4));
	return 0;
}

 

 总结:先找出每个成员变量的对齐数,再根据“偏移量为对齐数的整数倍处”对齐,最后最大对齐数即为结构体总大小。

结构体内存对齐的原因:

(1)平台原因

某些硬件平台只能在某些地址处取某些特定类型的数据。

(2)性能原因

为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存只需访问一次。

所以,设计结构体的时候要让占用空间小的成员尽量集中在一起。

6、修改默认对齐数

#pragma预处理指令可以改变默认对齐数

#pragma pack(8)//设置默认对齐数为8
struct S1
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

#pragma pack(1)//设置默认对齐数为1
struct S2
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
		return 0;
}

7、结构体传参

struct S
{
	char ch;
	int data[100];
};//结构体声明
struct S s = { 'A',{1,2,3} };//定义结构体体变量并初始化
void print1(struct S s)
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", s.data[i]);
	}
	printf("%c\n", s.ch);
}
void print2(struct S* s)
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", s->data[i]);
	}
	printf("%c\n", s->ch);
}
int main()
{
	print1(s);//传值调用
	print2(&s);//传址调用
	return 0;
}

如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。结构体传参的时候,要传结构体的地址。

二、位段

1、位段的声明

位段的声明与结构体类似,但:

a.位段的成员必须是int,unsigned int,signed int,char.

b.成员名后边有冒号和数字。

案例:

struct S
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct S));
	return 0;
}
//结果是8

为什么呢?下面就位段的计算给出解析。

2、位段的内存分配

注意:位段按照需要以4个字节(int)或者1个字节(char)的方式来开辟。

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;//10的二进制是1010-》所以3个比特位是010
	s.b = 12;//12的二进制是1100-》所以4个比特位是1100
	s.c = 3;//3的二进制是11-》所以5个比特位是00011
	s.d = 4;//4的二进制是100-》所以4个比特位是0100
	return 0;
}
//这个位段内存空间是怎样开辟的?

位段的跨平台问题:

a.int 位段被当成有符号数还是无符号数是不确定的

b.位段中最大的数目不能确定

c.从左向右还是从右向左分配未定义

d. 当第二个位段成员无法容纳第一个位段剩余的位时,是舍弃还是利用是不确定的

三、枚举

1、枚举类型的定义

枚举顾名思义就是列举

案例:

enum Day
{
	Monday,
	Tuesday,
	Wednesay,
	Thursday,
	Friday,
	Saturday,
	Sunday,
};
enum Sex
{
	male,
	female,
	secret,
};
enum Color
{
	red,
	green,
	blue,
};
enum Color
{
	red=2,
	green=8,
	blue=5,
};

 enum Day,enum Sex,enum Color都是枚举类型,{}中的内容是枚举常量,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。

2、枚举的优点

a.增加代码可读性

b.有类型检查

c.防止封装

d.便于调试

e.一次可以定义多个变量

使用案例:

enum Color
{
	red=2,
	green=8,
	blue=5,
};
int main()
{
	enum Color clr = green;
	printf("%d\n", clr);
	return 0;
}

四、联合(公用体)

1、联合类型的定义

联合类型的成员公用同一块内存空间(也叫共用体)

union Un
{
	int a;//4
	char c;//1
};


//共用
int main()
{
	union Un u;
	u.a = 0x11223344;
	u.c = 0x00;
	printf("%d\n", sizeof(u));//?

	printf("%p\n", &u);
	printf("%p\n", &(u.a));
	printf("%p\n", &(u.c));

	return 0;
}

 为什么出现上图这种情况呢?

哈哈,这是联合类型的独有特点——

2、联合的特点

 即联合变量的大小是最大成员的大小

练习题:判断当前计算机的大小端存储

法一:

int is_sort(int a)
{
	return *(char*)&a;
}
int main()
{
	int a = 1;//小端:01 00 00 00
	          //大端:00 00 00 01
	int ret = is_sort(1);
	switch (ret)
	{
	case 1:
		printf("小端\n");
		break;
	default:
		printf("大端\n");
		break;
	}
	return 0;
}

法二:

int is_sort()
{
	union U
	{
		char c;
		int i;
	};
	union U u;
	u.i = 1;
	return u.c;
}
int main()
{
    //小端:01 00 00 00
	//大端:00 00 00 01
	int ret = is_sort();
	switch (ret)
	{
	case 1:
		printf("小端\n");
		break;
	default:
		printf("大端\n");
		break;
	}
	return 0;
}

3、大小的计算

联合的大小至少是最大成员的大小

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

union U1
{
	char c[10];//每个字符变量对齐数为1
	int i;//对齐数为4
};
union U2
{
	short s[7];//每个short变量对齐数为2
	int i;//对齐数为4
};
int main()
{
	printf("%d\n", sizeof(union U1));
	printf("%d\n", sizeof(union U2));
	return 0;
}

分享到此结束,个人感觉位段那里有点小难,要多花功夫! 

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总GDP经济规模、贸易总额与国外直接投资均为最大,因此有着足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导产业链(半导设备及零部件、半导材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发烧的CPU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值