当前位置: 首页 > news >正文

嵌入式第十六课!!!结构体与共用体

一、结构体

结构体是一种数据类型,它的形式是这样的:

struct 结构体名

{        

        结构体成员语句1;

        结构体成员语句2;

        结构体成员语句3;

};

举个例子:

struct Student
{int id;char name[20];float score;
};

我们创建了一个数据类型Student,在这个声明里面,创建了三个变量: int型 id  ,   字符数组name[20] ,float型score;在声明的花括号  {  }  里面,要注意添加分号 “ ; ”,不然系统编译时会报错。

在主函数使用这个数据类型的时候:

struct Student
{int id;char name[20];float score;
};int main(void)
{s.id = 1;strcpy(s.name, "zhangsan");s.score = 97.5;printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score);return 0;
}

我们在主函数里定义了一个变量s,t它的数据类型Student,在给它赋值的时候,要按如上方式,依次赋值;

在使用结构体这种数据类型时,可以进行结构体嵌套:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{s.id = 1;strcpy(s.name, "zhangsan");s.score = 97.5;s.birthday.year = 2002;s.birthday.month = 3;s.birthday.day = 12;printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;

结构体初始化

在进行设定变量s时,可以直接进行初始化:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{struct Student s = {1, "zhangsan", 97.5, {2002, 3, 12}};printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;

结构体嵌套的部分用花括号 { } 隔开;

也可以对部分结构体成员进行初始化:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{struct Student s = {.id = 1,.score = 97.5,.birthday = {.year = 2002,}};
}	

其余未初始化的结构体成员变量为0;

为了在调用函数的时候,改变主调函数里struct 里结构体成员的值,我们可以通过指针来进行传参:

void printStudent(struct Student *p)
{printf("%d, %s, %f\n", p->id, p->name, p->score);
}
int main(void)
{struct Student a[3] = {{1, "zhangsan", 97.5},{2, "lisi", 98},{3, "wanghu", 95}};int len = sizeof(a) / sizeof(*a);printStudents(a, len);return 0;
}

需要注意的是,结构体成员指针不能写为(*p).id 或(*p) . name等,正确的编程规范应该为:p -> id

p -> name的格式;

使用指针传递的方式,占用字节较少,cpu运行速率较快;而普通的变量值传递会消耗很多空间,所以我们基本不用。

结构体数组

void printStudent(struct Student *p)
{printf("%d, %s, %f\n", p->id, p->name, p->score);
}void printStudents(struct Student a[], int len)
{int i;for(i = 0;i < len;++i){printStudent(a + i);}
}
int main(void)
{struct Student a[3] = {{1, "zhangsan", 97.5},{2, "lisi", 98},{3, "wanghu", 95}};int len = sizeof(a) / sizeof(*a);printStudents(a, len);return 0;
}

结构体成员按从前往后的顺序存储到数组里面;

同时,结构体数组元素之间是不能进行比较的,如a[0]和a[1],但是a[0].id 与 a[1].id之间是可以比较的。

结构体字节大小

在计算结构体大小前,我们要先厘清一个概念:

内存对齐:

在存储数据的时候,为了防止cpu为了访问一个数据,要读取两次内存空间的情况发生,在存储数据的时候,偏移量要可以整除存储的数据类型大小;

为了清晰易懂,请大家记住这三条准则,就可以又快又准确的计算出结构体所占的字节大小:

1.默认按CPU位数对齐(64位系统按8字节对齐),即最终地址为8的整数倍。

2.找结构体里最长字节的成员,以它的字节大小为基准对齐。

3.按照结构体的声明顺序,依次将成员保存在结构体内存中,最终保存的偏移量 / sizeof(成员) == 0。

如果是数组的话,就按其基类型的字节长度进行对齐;举个例子:

struct Demo
{char c;short d;int i ;
};int main(void)
{struct Demo s;printf("%d\n",sizeof(s));
}

sizeof (s) = 8字节;

0123456789
char  cshort  dint i

上图分别为存储变量的首地址,其中int 型变量占4个字节,加上前面的一共占8个字节;

这种方法势必会浪费一些空间,但是这种方式可以换取CPU的读写速率。

共用体

举个例子:

union Demo
{int i;short s;char c;
};

这是共用一段内存空间的数据类型,其共用体成员语句的内存空间相互彼此覆盖,打印值的话,系统会打印出最后一个覆盖的成员变量的值。

需要注意的是,共用体所有成员的地址都顶头写,我们可以利用这种特性来判断系统存储的方式是打断还是小端:

union Demo
{int i;short s;char c;
};int main(void)
{union Demo d;d.i = 1;union Demo *p;p = &d;fn(&d);if(d.c == 1){puts("little");}else{puts("big");}

枚举类型

这是一种自定义数据类型,并设定取值范围的数据类型:

enum Week
{Sun, Mon, Tue , Wes, Thu, Fri, Sat
};int main(void)
{enum Week w;w = Sun;printf("%d\n", w + 1);

在声明语句的时候,写入week所有的可能性,在调用时,使用这种数据类型的变量在枚举常量里任取其一:其实枚举常量里列举的取值可能性,实际上就是给整型常量0,1,2,3……等依次赋值;如果重置第一个常量Sun 赋值为2时,接下来的常量会依次赋为3,4,5,6……,如果从Mon开始重置赋值的话,Sun的值为0;

由此可以看出,它和整型是兼容的。

typedef定义类型

这种数据类型的实际上是给已有的数据类型换一个名字:

typedef int INT;typedef struct Demo
{int i;short s;char c;
}Demo, *PDEMO;typedef void (*pfn)(void);
typedef pfn ARRAY[10];int main(void)
{ARRAY a;INT s;printf("%lu\n" ,sizeof(a));return 0;
}

在主函数里,s是int型变量;a是一个由函数指针构成的元素个数为10的数组,其sizeof(a)= 80

http://www.lryc.cn/news/606452.html

相关文章:

  • 【Python修仙编程】(二) Python3灵源初探(9)
  • 7.31IO进程线程——标准IO函数
  • 在window中安装swow体验php协程
  • 【07】大恒相机SDK C#开发 —— 相机IO触发采集与信号输出
  • 2025年IntelliJ IDEA最新下载、安装教程,附详细图文
  • 最新PS 2025安装包下载与安装教程(Adobe Photoshop 2025 )
  • Linux731 shell工具;[]字符
  • imx6ull-驱动开发篇5——新字符设备驱动实验
  • 【MATLAB】(三)数据类型与运算符
  • 在MySQL中DECIMAL 类型的小数位数(Scale)如何影响分组查询?
  • 如何提前识别项目风险?主要方法分享
  • 【MATLAB】(二)基础知识
  • SAML、OpenID、OAuth、LDAP:解码 SSO 协议
  • Table-Render:基于 JSON Schema 的高性能 React 动态表格渲染器
  • 一万字讲解Java中的IO流——包含底层原理
  • 开启云服务器mysql本地连接(is not allowed to connect to this mysql server)
  • java关键字2—this和super
  • 前端ESLint扩展的用法详解
  • 468. 验证IP地址
  • 图论-最短路 Bellman-Ford算法
  • sqli-labs:Less-12关卡详细解析
  • C++(模板,智能指针)
  • 力扣-102. 二叉树的层序遍历
  • 数据治理:数字化时代的 “治” 与 “理” 之道 —— 破解企业数据资产困局
  • 脚手架搭建React项目
  • 解决Python ModuleNotFoundError:使用python -m的妙招
  • Spring MVC体系结构和处理请求控制器
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-52,(知识点:简单一阶低通滤波器的设计,RC滤波电路,截止频率)
  • 【Kubernetes 指南】基础入门——Kubernetes 201(三)
  • 【Linux】的起源 and 3秒学习11个基本指令