10.自定义类型:结构体

本篇博客探讨结构体的进阶应用(注意:本博客未梳理结构体基础知识【包括结构体类型的基础声明,变量的创建与初始化,结构体的输出,成员访问操作符等】,默认读者已经掌握)

一、结构体的声明

1.结构体的特殊声明:匿名结构体

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

匿名结构体的重命名:使用typedef关键字

typedef struct Node 
{ 
	int a; 
	char b; 
	float c; 
}Node;

之后创建结构体变量的时候,可以直接Node s={…},前面的struct可以省略掉
注意:匿名的结构体类型,若没有对结构体类型重命名,只能使用一次

2.结构体的自引用:以链表的节点为例

struct Node 
{ 
	int data; //数据域
	struct Node* next;//指针域 
}; 

这样的代码可以无限自引用下去,并且保证了结构体的大小不会是无穷大

二、结构体内存对齐

1.对齐规则

(1)结构体第一个成员对齐到和结构体起始位置偏移量为0的地址处
(2)其它成员变量要对齐到对齐数的整数倍的地址处对齐数=min{编译器默认的一个对齐数,该成员变量的大小(单位是字节)}
①VS中默认对齐数为8
②Linux中gcc无默认对齐数,对齐数就是成员自身的大小
(3)结构体总大小=所有成员最大对齐数的整数倍
(4)如果嵌套了结构体,嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍处
结构体整体大小=最大对齐数(包括嵌套结构体中成员的对齐数)的整数倍

//例1
struct S1
{ 
	double d; 
	char c; 
	int i; 
}; 
printf("%d\n", sizeof(struct S1));//输出16

图片解析
解析

//例2
struct S2 
{ 
	char c1; 
	struct S1 s1; //结构体里面嵌套结构体
	double d; 
}; 
printf("%d\n", sizeof(struct S2)); //输出32

解析
注:#pragma这个预处理指令可以修改编译器的默认对其数,当结构体对齐方式不满足编程需要的时候我们可以自己修改对齐数

#include <stdio.h> 
#pragma pack(1)//设置默认对⻬数为1 
struct S //结构体的内存布局按照对齐数为1进行设置
{ 
	char c1; 
	int i; 
	char c2; 
}; 
#pragma pack()//取消设置的对⻬数,还原为默认 
int main() 
{ 
	printf("%d\n", sizeof(struct S)); //6
	return 0; 
} 

三、结构体传参:传递一个结构体对象的时候,要传结构体的地址(避免结构体过大导致压栈的系统开销过大)

例如:下面代码首选print2函数

struct S 
{ 
	int data[1000]; 
	int num; 
}; 
struct S s = {{1,2,3,4}, 1000}; 
//结构体传参 
void print1(struct S s) 
{ 
	printf("%d\n", s.num); 
} 
//结构体地址传参 
void print2(struct S* ps) 
{ 
	printf("%d\n", ps->num); 
} 
int main() 
{ 
	print1(s); //传结构体 
	print2(&s); //传地址 
	return 0; 
} 

四、结构体实现位段

1.位段的定义(除了以下两点外其它与结构体相同)

(1)位段的成员可以是int,unsigned int,signed int或者是char
(2)位段的成员名后面有一个冒号和数字,表示该成员占多少个bit位

struct A 
{ 
	int _a:2; //_a占2个bit位
	int _b:5; //_b占5个bit位
	int _c:10; //_c占10个bit位
	int _d:30; //_d占30个bit位
};

2.位段的内存分配(测试环境:VS2022)

(1)位段的空间:按照需要以4个字节(int)或1个字节(char)开辟
代码测试样例

原理解析:
a. VS2022从右向左开辟空间,本代码位段中均为char,因此一次开辟一个字节(8个 bit位)
b. 当剩下的位置不够下一个成员使用时,VS将其浪费,再开辟出新的一个字节
原理解析

3.位段的跨平台问题

(1)int位段被当成有符号整型还是无符号整型不确定
(2)位段中最大位的数目不确定(比如16位机器中int占2个字节)
(3)位段中成员的内存是从左向右还是从右向左分配,C标准未定义
(4)剩余空间不够下一个成员使用,是否浪费掉剩余空间不确定
因此,位段可以达到和结构体相同的效果,并且可以很好地节省空间,但是有跨平台的问题存在

4.位段使用的注意事项:不能对位段的成员使用&操作符,因为可能拿不到地址
位段的几个成员共用一个字节,但是一个字节内部的bit位是没有地址的,所以不能用scanf,只能先输入一个值放在变量中,再赋值给位段成员。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值