语言进阶(六)自定义类型详解结构体枚举联合腾讯云开发者社区

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

我们以描述一个学生为例,

一个学生变量,用性别,年龄,姓名描述。

打印效果

匿名结构体类型

在上述代码中,并未给结构体加上标签,所以我们在使用时无法直接使用其变量,在;前创建变量,且只能用一次。

那么问题来了?

在上述代码的基础上,下面的代码是否合法?

该等式并不成立,在c语言中,虽然他们的成员变量是相同的,但是他们的结构体类型不相同,所以编译过程会报错,不同类型的成员互不兼容。

在这里,我们引入数据结构的部分内容来理解。

这个代码能否帮助我们从一个数字串联到下一个数字?

从表面上看,确实从一个结构体中能找到下一个结构体中的数据,但是

如果可以,那sizeof(struct Node)是多少?

将会是一个无穷大的量,无法计算,所以不可行。

正确的自引用方式:

这里我们如何理解呢?

这样就可以串联链表中的每一个数字,结构体引用结构体,(类似于递归),这就是结构体的自引用。

有了结构体类型,那么如何定义结构体成员变量呢?

初始化:定义变量的同时赋初值

结构体嵌套初始化

在掌握结构体的基础知识后,我们想要计算一下结构体的大小,那么是如何计算的呢?

结构体在计算大小时会出现一个问题,那就是结构体的内存对齐

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

VS中默认的值为8

Linux中的默认值为4

对规则的解读:

什么叫做偏移量?

让我们通过练习来熟悉内存对齐的使用

练习一

请问该结构体的大小是多少?

可能是6,也可能是其他,让我们运行一下程序。

结果为 12,那么如何得出结构体的大小为 12 呢?

char c1 占1个字节 ,从结构体的起始位置开始存储。

int i 占4个字节,vs环境下他的对齐数为4,所以他在地址中要从4的倍数开始储存。

char c2 占1个字节, 对齐数为1,所以它在int 后又占1个字节。

此时计算大小为9,总大小应该符合总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍,最大对齐数为4,所以总大小应为12.

内存示意图:

练习二

char c1占一个字节,从结构体的起始位置开始存储。

char c2占一个字节,对齐数为1.

int i 占4个字节,vs环境下他的对齐数为4,所以他在地址中要从4的倍数开始储存。

此时结构体的总大小是8个字节,为最大对齐数4的倍数。

示意图:

显示结果

练习三

练习四

结构体的嵌套问题

大部分的参考资料都是这样说的:

假如在 32 位 的机器上, 一次读取数据只能读取 4个字节,那么在不考虑并对齐的情况下, int类型的数据要读取两次才能完整计算, 而在考虑对齐的情况下,int 只需读取一次。

总的来说:

那在设计结构体的时候,我们既要满足对齐,又要节省空间,怎样才能做到?

让占用空间小的成员尽量集中在一起

s1 和 s2类型的成员一模一样,但是 s1 和 s2 所占空间的大小有了一些区别。

#pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数

这里我们将默认对齐数修改为8,所以打印的结果为 12

这里设置默认对齐数为1,就相当于连续存放,结构体的大小为 1+4+1=6

结论:

结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。

当我们有一个结构体类型,又创建了一个结构体变量,当我们使用这个变量时,没有直接使用,而是传给其他函数使用,我们可以选择传送这个结构体变量的值,也可以选择传送这个结构体变量的地址

我们向print函数分别传送了struct 结构体本身,以及结构体的地址,那如果比较的话,print1 和 print2 哪个更好?

答案是:首选print2函数。

原因:

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

举一个例子,传结构体本身的话,这个结构体内部有int i[10000]的数据,那我们就要传送10000个整形数据,但是如果我们传送的是结构体的地址的话,首先指针总共就只占用4个字节,我们可以通过这4个字节来找到并操作所指向的10000个整形数据。大大节省了空间和时间。

值传递:函数的形参值传递,是拷贝实参的内容到形参中并且开辟出同等大小的空间来存储的过程,在这个过程中回发生压栈,如果结构体成员过多,压栈的空间就越多,导致空间上的浪费。

址传递:直接把实参的地址传递过去,而使用的空间仅仅是4/8个字节,而且地址传递还能对实参进行修改,所以一般结构体传参都是传址。

结论:

结构体传参的时候,要传结构体的地址。

1.位段的成员必须是 int ,unsigned int ,或 signed int

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

A就是一个位段类型

那位段A的大小是多少?

我们可能会这样计算:2+5+10=17,但是位段的内存分配并不是简单的相加减等等。

这里位段的位是 二进制位,为什么要引入位段的概念呢?我们要知道,如果在内存中要存储 0 、1、2、3这样的数据,所占的空间大小最多才为2个bit位,但是我们创建了一个int类型占4个字节,32个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位

位段一次开辟4个字节的空间,将a,b,c,d依次放入

但是我们发现将a,b,c已经占了17个bit位了,d 占30个bit位无法存入这个空间中,我们就需要再开辟一个4个字节的空间大小。所以总共占据8个字节进行存储。

但是我们搞清楚了空间的大小,却不清楚数据如何进行存放。d存放的可能方式

1.将第一个开辟的空间剩余的13个bit位占满后,在第二个空间中存放17个bit位。

2.因为无法整体存入第一空间中,所以从第二个空间进行存放,第一个空间剩余的内存被浪费掉。

如何进行存放,我们还不是特别清楚。

所以这里的第三条内存分配的规则就讲述了位段跨平台的特点,其实在不同的编译器上存放的规则也不相同,但是上述2种存放的方法都对,不过在不同的平台存放的形式有所差异。

2.位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32)

3.位段的成员在内存中是从左向右分配,还是从右向左分配标准尚未定义。

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

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

枚举顾名思义就是一一列举。

把可能的取值一一列举。

比如我们现实生活中:

这里就可以使用枚举了。

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。 {}中的内容是枚举类型的可能取值,也叫 枚举常量 。

这些可能取值都是有值的,默认从0开始,一次递增1。如下图所示:

当然定义的时候也可以赋初值,例如:

为什么使用枚举?

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

枚举的优点:

联合也是一种特殊的自定义类型。这种类型定义的变量也包含了一系列的成员,特征是这些成员共用一块空间(所以联合也叫共用体)。

比如

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

那么联合体成员变量是如何存放入内存的?

我们看一下代码:

i 和 c 如何进行存储?

来看打印结果

我们会发现i 和 c 占用了同一块空间。

i 和 c 会占用同一块空间,这就是联合体(共用体)的特点。联合体的成员会共用一块空间。

对联合体的特点我们清楚以后,那我们什么时候使用联合体呢?

以上面的 char c 、 int i 举例,在我们只使用char c 或 int i 时我们可以使用联合体。如果有多个成员,使用c的时候,i的值也会发生相应变化,使用i的时候,c的值也会发生相应的变化,所以这两个变量不能同时使用。

举一个例子:

当联合体中存储两个不同的值时,内存中的结果是显示的。

打印的结果是什么呢?

那么 为什么呢?

u=0x55 改变了原来 i 的首字节44的存储,所以共用一块空间的结构体成员在使用时会互相影响。

面试题

判断当前大小计算机的大小端存储

这是普通方法的代码实现:

下面我们用联合体的形式来判断当前机器的大小端存储。

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

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

比如:

第一个打印结果, char 类型的数组占5个字节,该联合体最大对齐数是4,所以要浪费3个字节的空间,占8个字节。

第二个打印结果, short类型的数组占14个字节,在联合体最大对齐数是4,所以要浪费2个字节的空间,占16个字节。

THE END
0.语法结构类型是什么粘着语也是一种重要的语言结构类型.粘着语的主要特点是没有内部屈折,每一个变词语素只表示一种语法意义,而每种语法意义也总是由一个变词语素表示.因此,一个词如果要表示三种语法意义就需要有三个变词语素.此外,粘着语的词根和变词语素之间的结合并不紧密.两者都有相当大的独立性,变词语素好像是粘附在词根上jvzquC41sd4{wx~gdcth0lto1zlf/zzguvopp8vwguzjqw44;3k:3o5833>fem<;79;e6?::3e;83;h0jvsm
1.结构体类型是什么?如何定义?(2)结构体类型与整型、浮点类型、字符类型等类似,只是数据类型,而非变量。 (3)定义好一个结构体类型后,并不意味着编译器会分配一块内存单元存放各个数据成员,它只是告诉编译系统结构体类型由哪些类型的成员构成、各占多少字节、按什么格式存储,并把它们当作一个整体来处理。 jvzquC41yy}/k}hcuv4dp8sgyu532;5335603A5636798;:0ujznn
2.JavaScript数据类型和数据结构编程语言都有内置的数据结构,但各种编程语言的数据结构常有不同之处。本文尝试列出 JavaScript 语言中内置的数据结构及其属性。它们可以用来构建其他的数据结构。jvzq<84fgxkmqyjt0ou{kuqc0qxh1ƒm/EP5eqlx1Ygh0Lj{cUexjr}4Fcvg`u}wwev{sg|
3.定义数据结构中重复定义结构体类型的作用是什么?定义数据结构中重复定义结构体类型的作用是为了更加直观的表达数据类型。比如Position FindMin(SearchTree T),完全可以写成TreeNode* FindMin(TreeNode* T),只是名列前茅种方法更为直观一些,表示传入的是一颗树,而返回的是最小值所在的位置结点。 结构体的定义 jvzq<84yyy4nqknngvxbkw3qti5bdxzv1DHT1;56756/j}rn
4.写出下列是什么结构类型的短语(如偏正、动宾、主谓……)1、来势写出下列是什么结构类型的短语(如偏正、动宾、主谓……)1、来势汹汹2、声名狼藉3、穷形尽相4、无精打采5、不知所措6、甘拜下风7、修了三年8、苦得他像一个木偶人9、放了一天假10、生活一辈子11、丢了一本书12、贴着一幅画13、北京立交桥14、最后一课15、天上的街市 扫码下载作业帮搜索答疑一搜即得 答案解析 查看更多优质jvzquC41yy}/|‚gcpi4dqv4swgyukxs1d8836o;cee;cd?=:57l7;o:f95:39m8d0jznn
5.java中node类型是什么数据mob649e8166179a的技术博客Java中的Node类型是什么数据 在Java中,Node(节点)是一种用于表示数据结构的基本元素。它通常用于构建树、链表、图和其他数据结构。在这篇文章中,我们将深入探讨Java中的Node类型以及如何使用它。 什么是Node类型 Node类型是指在一个数据结构中,用于存储数据元素的对象。每个节点都包含一个数据项和一个或多个指向其他jvzquC41dnuh0>6evq4dqv4wa3<29>:291=5;@<:7
6.C语言struct结构类型定义和结构变量说明c++struct这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数jvzquC41dnuh0lxfp0tfv8}wgh{329=1ctzjeuj1fgzbkux168:59@5
7.C#语言基础——结构体和枚举类型全面解析C#教程【技术要点】定义jiegouti类型的结构体,原有3个结构变量,fenshu,name,kecheng,新增一个变量public int[] shuzu,而这个结构元素还可以包含一个新结构体,在主函数中重新(new 初始化)定义一个参数接收这个新的结构变量,然后输出name,返回一个字符串。 【案例3】在上面jiegouti类型的结构体元素还可以包含另外一个结构jvzquC41yy}/lk:30pku1jwvkerf1A=46:4ivv
8.判断下列短语是什么结构类型?1.十分高兴2.高高的个子3.广州的判断下列短语是什么结构类型?1.十分高兴 2.高高的个子 3.广州的公园 4.写得很清楚 5.去北京 6.不马上来 7.穿上衣服跳下床开门出去 8.经理叫我们明天加班9.一群看热闹的 10.所见所闻 11.秉公办事 12.身体内部用层次分析法分析下列结构.1.我们班的同学参加了拔河比赛.2.他很喜欢唐诗.3.我们公司最近推出了一项新业务.4.他们jvzquC41yy}/|‚gcpi4dqv4swgyukxs15c9b:n8fc9=13:=7h:;:g?k832jbgo5;0jznn
9.一文教你如何快速学会Go的struct数据类型Golang结构是表示字段集合的用户定义类型。它可以用于将数据分组为单个单元而不是将每个数据作为单独的值的地方。本文就来和大家聊聊Go中struct数据类型的使用,需要的可以参考一下+ 目录 GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想靠AI翻身,你先需要一个靠谱的工具!】 什么是结构体 结构是表示字段jvzquC41yy}/lk:30pku1jwvkerf1;<94:8/j}r