结构体枚举联合详解(附例题解析)

目录:

结构体的初始化

结构体的内存对齐

位段

-->位段的内存分配

 -->位段的跨平台问题

枚举的优点

 联合的特点 

联合体的大小计算


结构体的初始化

struct Stu
{
    char name[20];
    int age;
    char sex[5];
    char id[20];
};//注意这个分号不能丢

定义一个结构体这个结构体中有四个元素分别为:name;age;sex;id

对结构体初始化:

struct Stu a = { "张3",4,"男","1800" };

结构体的嵌套初始化:

struct Dodo
{
    struct Stu b;
    struct Dodo* next;
};
int main() 
{
    struct Dodo chx= { {"王5",5,"公","123123"},NULL };

    return 0;
}

结构体的内存对齐

结构体的对齐规则:

1.结构体的第一个成员在结构体变量偏移量为0的地址处

2.其他成员变量要对齐到 某个数字(对齐数)的整数倍的地址处

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

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

4.如果嵌套了结构体,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是

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

---------------------------------------------------------------------------------------------------------------------------------

例题Top1:

struct S2
{
    char c1;
    char c2;
    int i;
};

1.分别判断结构体中每个成员的对齐数 int 对齐数为4,char 对齐数为1,vs中默认对齐数为8

-->   char c1在内存中占用一个字节,对齐数->1,且为结构体的第一个成员要放在偏移量为0的位置 

-->   char c2在内存中占用一个字节,对齐数->1,偏移量跟对齐数都是1,所以紧接着内存

-->   int i在内存中占用4个字节,对齐数->4,要在偏移量为4的倍数中开始

数一数一共占用的8个框框也就是8个字节,结构体成员中的最大对齐数(int)为4,8是4的倍数

所以结构体的大小为 sizeof(struct S2)值为 8

  例题Top2:

struct S3
{
    double d;
    char c;
    int i;
};

 1.分别判断结构体中每个成员的对齐数 int 对齐数为4,char 对齐数为1,double 对齐数为8          vs中默认对齐数为8

-->   double d在内存中占用8个字节,对齐数->8,且为结构体的第一个成员要放在偏移量为0的位置 

-->   char 1在内存中占用1个字节,对齐数->1,偏移量和对齐数都是1紧接着存

-->   int i 在内存中占用4个字节,对齐数->4,但char后的偏移量为9,不是4的倍数所以int i要放在偏移量为12的位置,那么如图所示struct S3的大小为15,但是实际上struct的大小要是成员中最大对齐数的倍数 也就是double 8 的倍数,所以最终的大小sizeof(struct  S3)为16

 

Q1:为什么会存在内存对齐呢 

A1:平台原因->不是所有硬件平台都支持访问任意地址上的数据的

      性能原因->数据结构应该尽可在自然边界上对齐(尤其是栈),对齐的内存仅需一次访问 

 总结:结构体的内存对齐是拿空间来换取时间

---------------------------------------------------------------------------------------------------------------------------------

位段

Q1: 什么是位段

A:位段的成员必须是int unsigned int 或 signed int, char其实也行

位段的成员名后有一个冒号和一个数字。

        

 位段可以根据需求来分配空间,某些成员并不需要32个bit位 ,位段是不对齐的

-->位段的内存分配

-->位段的空间上是按照四个字节(int)或者一个字节(char)的方式来开辟的

-->位段涉及很多不确定因素,所以位段是不跨平台的

struct a
{
//先开辟32个字节
    int a : 2;//32-2=30
    int b : 5;//30-5=25
    int c : 10;//25-10=15
    int d : 30;//15<30,再开一个32个字节的空间 32-30=2
};

-->先开辟32个字节,a分配2后剩下30b分配后剩25,c分配后剩下15 此时剩下15不够开辟d

那么再开32个字节来存放d

-->c语言中并没有明确规定d会不会使用上一次所开辟空间的剩余所以这也是不能移植的原因

-->位段是时间换空间的做法

 

 -->位段的跨平台问题

1.int 被当做有符号数还是无符号数是不确定的

2.位段中最大位的数目不能确定。(16位最大16,32位最大32,写成28在16位机器上就会有问题)

3.位段中的成员从左向右分配还是从右向左分配没有明确的定义

4.当一个结构包含两个位段,第二个成员比较大的话,无法容纳第一个位段的空位时,是舍弃空位还是利用这事不确定的

---------------------------------------------------------------------------------------------------------------------------------

枚举的优点

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

枚举的优点:

1.增加代码可读性和可维护性

2.和#define 定义标识符比较 枚举有类型检查更加严谨

3.为了防止命名污染

4.便于调试,使用方便一次可以定义多个常量  

看代码段中的注释应该能找到规律

enum Day
{
    fir,//为0
    roc,//为1
    top = 5,//为5
    top2,//为6
    am = 200,//为200
    ak//为201
};

 联合的特点 

联合的成员是共用同一块内存空间,这样一个联合体的大小,至少是最大成员的大小(因为联合至少得有保存最大的那个成员的能力)

可以用共用体来判断大小端的存储:打印1的话那么就是小端存储

int test()
{
	union
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}
int main()
{
	int a = test();
	printf("%d", a);//打印的是1
	return 0;
}

 把联合体中u.i赋值1那么在内存中是01 00 00 00,当你返回u.c时由于u.c是char型只能访问一个字节,所以就会把01(十进制的1)传回去

 --------------------------------------------------------------------------------------------------------------------------------

联合体的大小计算

 -->联合体的大小至少是最大成员的大小 

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

 

 按照这么来说联合体Un的大小应该为5,但是5并不是最大对齐数4倍数,所以实际上Un的大小为8

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Obto-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值