【C语言结构体】用户自定义类型--结构体,结构体传参,位段,联合体和枚举【图文详解】

欢迎来CILMY23的博客喔,本篇为【C语言结构体】用户自定义类型--结构体,结构体传参,位段,联合体和枚举【图文详解】,感谢观看,支持的可以给个一键三连,点赞关注+收藏。

 前言

上一篇(http://t.csdnimg.cn/ruaRw)我们讲到C语言中,用户可以自定义类型,结构体,

 本期将讲解结构体的传参,和位段,联合体以及枚举类型。

浮点数的取值范围:float.h 整型的取值范围:limits.h

今日语句分享:一个人走慢点也并无害处,因为他的辉煌不在于行走,而在于亲身体验。

目录

一、结构体传参

二、位段

三、联合体

四、枚举 


一、结构体传参

结构体传参也分传值调用和传址调用

首先我们来看传值调用:

struct S
{
	int b[100];
	int num;
};

void print1(struct S t)
{
	printf("%d %d %d %d\n", t.b[0], t.b[1], t.b[2], t.num);
}

int main()
{
	struct S s = { {1,2,3},100 };
	print1(s);
}

结果如下:

 

我们接着来看传址调用

void print2(struct S* pt)
{
	printf("%d %d %d %d\n", pt->b[0], pt->b[1], pt->b[2], pt->num);
}

int main()
{
	struct S s = { {1,2,3},100 };
	print2(&s);
}

结果如下:

 

二、位段

结构体传参后,我们得讲结构体的另外一个能力---位段

2.1什么是位段

位段就是以下这样的代码,它是基于结构体实现的,它的出现是为了节省空间位是二进制位的意思

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 15;
};

位段的声明和结构体声明是类似的,有两个不同:

1.    位段的成员必须是int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他类型。
2.    位段的成员名后边有⼀个冒号和⼀个数字。 

2.2位段的大小

位段的出现既然是为了节省空间,那上面那段代码如何解读呢?

如下所示:

实际上在冒号后面的数字代表的是bit,有几个数字就有几个bit位置。 

#include <stdio.h>

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 15;
};

struct B
{
	int _a;
	int _b;
	int _c;
	int _d;
};

int main()
{
	struct A a;
	struct B b;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(b));
}

 结果如下:

 解释:

2.3位段的内存分配

 看以下这段代码:

struct S
{
	char a : 3; 
	char b : 4; 
	char c : 5; 
	char d : 4;
};

int main()
{
	struct S s = { 0 };
	printf("%d ",sizeof(s));
}

 结果如下:

我们看到大小是3,但是实际上 

1.    位段中内存的空间使用是从左到右还是从右到左使用是不确定的

2.    当前面使用,剩余的空间不足下一个成员存储,是否继续使用剩余的空间是不确定的。

那我们接着看下面这段代码: 

#include <stdio.h>

struct S
{
	char a : 3; 
	char b : 4; 
	char c : 5; 
	char d : 4;
};

int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

	printf("%d ",sizeof(s));
}

我们假设在vs上内存分布是从右到左的 

 这里有三个字节

 首先a分配三个bit位,a的数值是10,转换成二进制是1010,因为只分配3个bit,所以存入010,b的数值是12,转换成二进制是1100,因为分配4个bit,而之前使用剩余空间足够,我们继续存入,c的数值是3,转换成二进制是011,而分配5个bit,所以存入011,其余用0补齐,d的数值是4,转换成二进制是100,分配4个bit,由于之前分配给c的bit位置不够了,我们再拿一个字节来存d,将100存入,然后再用0补齐

那在vs上到底是如何呢?

结果是显而易见的,正如我们所想的这样

2.3位段的跨平台问题 

1.    int在位段中被当成有符号数还是无符号数是不确定的。
2.    位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。)
3.    位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.    当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。 

2.4 总结

位段总结:

1.    位段的成员可以是int,unsigned int,signed int 或者是char 等类型。

2.    位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。

3.    位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。 

三、联合体

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体。

3.1联合体的类型声明

 union是联合体的关键字,我们对其声明也跟结构体类似

union U
{
	char c;
	int i;
};

3.2联合体的大小和内存分布

联合体的大小:

union U
{
	char c;
	int i;
};

int main()
{
	union U u = { 0 };
	printf("%d ", sizeof(union U));
}

结果如下: 

 

那为什么是4呢?这还要从联合体的成员地址看起

 

我们通过上图可以看到每个成员的地址的都是一样的 ,这说明联合体当中每个成员都是用同一个空间,所以给联合体其中一个成员赋值,其他成员的值也跟着变化。

 3.3联合体大小的计算

union Un1
{
	char c[5];
	int i;
};

union Un2
{
	char c[7];
	int i;
};
int main()
{
	//下⾯输出的结果是什么?
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

 结果如下:

 联合体同样涉及内存对齐

所以un1对齐到8字节,同样un2也是对齐到8字节

总结:

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

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

3.4联合体的练习 

写一个程序判断大小端字节序(这个我们之前写过:http://t.csdnimg.cn/gIUL5) 

int check_sys()
{
	union U
	{
		int i;
		char c;
	}u;
	u.i = 1;
	return u.c;
}

 那我们可以利用这个联合体共用一个空间的特性来解决大小端,然后设计一个函数,最后返回c 的值即可。

四、枚举 

4.1枚举的类型声明

枚举顾名思义就是一一列举。
把可能的取值一一列举。

就比如以下这段代码: 

enum Day
{
    Mon,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};

 以上定义的enum Day是枚举类型。{}中的内容是枚举类型的可能取值,也叫枚举常量。这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

enum Day//星期
{
	Mon = 8,
	Tues = 10,
	Wed = 99,
	Thur = 54,
	Fri = 55,
	Sat = 22,
	Sun = 66
};

4.2枚举的优点 

我们可以使用   #define 定义常量,为什么非要使用枚举?

枚举的优点:
1.    增加代码的可读性和可维护性
2.    和#define定义的标识符比较枚举有类型检查,更加严谨。
3.    便于调试,预处理阶段会删除#define 定义的符号
4.    使用方便,⼀次可以定义多个常量
5.    枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用 

4.3枚举类型的使用

 假设我们想描述一个人的性别, 我们就可以用枚举常量给枚举类型的变量赋值。那是否可以拿整数给枚举变量赋值呢?在C语言中是可以的,但是在C++是不行的,C++的类型检查比较严格。

enum Sex
{	
	MALE,
	FEMALE,
	SECREAT
};

int main()
{
	enum Sex S = FEMALE;
	return 0;
}

感谢各位同伴的支持,本期位段篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。   

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值