[应用相关] 【转】嵌入式 C | 结构体完全笔记,收藏!

[复制链接]
5746|52
 楼主| 盗铃何须掩耳 发表于 2022-5-6 17:04 | 显示全部楼层


结构体的搭档

虽然结构体的出现能够让我们有一个更科学的数据结构来管理数据,但是每次使用结构体都需要struct...,未免显得有些冗长和麻烦。有了typedef的助攻,我们就可以很轻松地给结构体类型起一个容易理解的名字:


  1. typedef struct date
  2. {
  3.     int year;
  4.     int month;
  5.     int day;
  6. } DATE;//为了区分,一般用全大写

  7. int main(void)
  8. {
  9.     DATE* date;
  10.     ...
  11. }
甚至还可以顺便给它的指针也定义一个别名:
  1. typedef struct date
  2. {
  3.     int year;
  4.     int month;
  5.     int day;
  6. } DATE, *PDATE;




 楼主| 盗铃何须掩耳 发表于 2022-5-6 17:06 | 显示全部楼层
进阶

我们还可以利用typedef来简化一些比较复杂的命令。

比如:

  1. int (*ptr) [5];

我们知道这是一个数组指针,指向一个5元素的数组。那么我们可以改写成这样:

  1. typedef int(*PTR_TO_ARRAY)[3];
这样就可以把很复杂的声明变得很简单:
  1. PTR_TO_ARRAY a = &array;
取名的时候要尽量使用容易理解的名字,这样才能达到使用typedef的最终目的。



 楼主| 盗铃何须掩耳 发表于 2022-5-6 17:11 | 显示全部楼层
共用体

共用体也称联合体。


初始化

共用体不能在同一时间存放多个成员,所以不能批量初始化

  1. nion data
  2. {
  3.     int i;
  4.     char ch;
  5.     float f;
  6. };

  7. union data a = {520};        //初始化第一个成员
  8. union data b = a;            //直接使用一个共用体初始化另一个共用体
  9. union data c = {.ch = 'C'};  //C99的特性,指定初始化成员


 楼主| 盗铃何须掩耳 发表于 2022-5-6 17:17 | 显示全部楼层


枚举

枚举是一个基本的数据类型,它可以让数据更简洁。

如果写一个判断星期的**,我们当然可以使用宏定义来使代码更加易懂,不过:

  1. #define MON 1
  2. #define TUE 2
  3. #define WED 3
  4. #define THU 4
  5. #define FRI 5
  6. #define SAT 6
  7. #define SUN 7

这样的写法有点费键盘。那么枚举就简单多了:

  1. enum DAY
  2. {
  3.       MON=1, TUE, WED, THU, FRI, SAT, SUN
  4. };
[color=rgba(127, 194, 194, 0.498)]

**注意:**第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

[color=rgba(127, 194, 194, 0.498)]❞

枚举变量的定义和声明方法和共用体一样,也可以省略枚举名,直接声明变量名。

  1. //Example 06
  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. int main()
  5. {

  6.     enum color { red = 1, green, blue };

  7.     enum  color favorite_color;

  8.     printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");
  9.     scanf("%d", &favorite_color);

  10.     //输出结果
  11.     switch (favorite_color)
  12.     {
  13.     case red:
  14.         printf("你喜欢的颜色是红色");
  15.         break;
  16.     case green:
  17.         printf("你喜欢的颜色是绿色");
  18.         break;
  19.     case blue:
  20.         printf("你喜欢的颜色是蓝色");
  21.         break;
  22.     default:
  23.         printf("你没有选择你喜欢的颜色");
  24.     }

  25.     return 0;
  26. }
执行结果如下:
  1. //Consequence 06
  2. 请输入你喜欢的颜色: (1. red, 2. green, 3. blue): 3
  3. 你喜欢的颜色是蓝色

也可以把整数转换为枚举类型:

  1. //Example 07

  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. int main()
  5. {
  6.     enum day
  7.     {
  8.         saturday,
  9.         sunday,
  10.         monday,
  11.         tuesday,
  12.         wednesday,
  13.         thursday,
  14.         friday
  15.     } workday;

  16.     int a = 1;
  17.     enum day weekend;
  18.     weekend = (enum day) a;  //使用强制类型转换
  19.     //weekend = a; //错误
  20.     printf("weekend:%d", weekend);
  21.     return 0;
  22. }

运行结果如下:

  1. //Consequence 07
  2. weekend:1



 楼主| 盗铃何须掩耳 发表于 2022-5-6 17:19 | 显示全部楼层
位域

C语言除了开发桌面应用等,还有一个很重要的领域,那就是「单片机」开发。单片机上的硬件资源十分有限,容不得我们去肆意挥洒。单片机使一种集成电路芯片,使采用超大规模集成电路技术把具有数据处理能力的CPU、RAM、ROM、I/O、中断系统、定时器/计数器等功能(有的还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工控领域使用广泛。

对于这样的设备,通常内存只有256B,那么能够给我们利用的资源就十分珍贵了。在这种情况下,如果我们只需要定义一个变量来存放布尔值,一般就申请一个整型变量,通过1和0来间接存储。但是,显然1和0只用1个bit就能够放完,而一个整型却是4个字节,也就是32bit。这就造成了内存的浪费。

好在,C语言为我们提供了一种数据结构,称为「位域」(也叫位端、位字段)。也就是把一个字节中的二进制位划分,并且你能够指定每个区域的位数。每个域有一个域名,并允许程序中按域名进行单独操作。

使用位域的做法是在结构体定义的时候,在结构体成员后面使用冒号(:)和数字来表示该成员所占的位数。

  1. //Example 08
  2. #include <stdio.h>

  3. int main(void)
  4. {
  5. struct Test
  6. {
  7.   unsigned int a : 1;
  8.   unsigned int b : 1;
  9.   unsigned int c : 2;
  10. } test;

  11. test.a = 0;
  12. test.b = 1;
  13. test.c = 2;

  14. printf("a = %d, b = %d, c = %d\n", test.a, test.b, test.c);
  15. printf("size of test = %d\n", sizeof(test));

  16. return 0;
  17. }

运行结果如下:

  1. //Consequence 08
  2. a = 0, b = 1, c = 2
  3. size of test = 4

如此一来,结构体test只用了4bit,却存放下了0、1、2三个整数。但是由于2在二进制中是10,因此占了2个bit。如果把test.b赋值为2,那么:

  1. //Consequence 08 V2
  2. a = 0, b = 0, c = 2
  3. size of test = 4

可以看到,b中的10溢出了,只剩下0。

当然,位域的宽度不能够超过本身类型的长度,比如:

  1. unsigned int a : 100;

那么就会报错:

  1. 错误        C2034        “main::test::a”: 位域类型对位数太小

位域成员也可以没有名称,只要给出类型和宽度即可:

  1. struct Test
  2. {
  3.     unsigned int x : 1;
  4.     unsigned int y : 2;
  5.     unsigned int z : 3;
  6.     unsigned int : 26;
  7. };

无名位域一般用来作为填充或者调整成员的位置,因为没有名称,所以无名位域并不能够拿来使用。

[color=rgba(127, 194, 194, 0.498)]

C语言的标准只说明unsigned int和signed int支持位域,然后C99增加了_Bool类型也支持位域,其他数据类型理论上是不支持的。不过大多数编译器在具体实现时都进行了扩展,额外支持了signed char、unsigned char以及枚举类型,所以如果对char类型的结构体成员使用位域,基本上也没什么问题。但如果考虑到程序的可移植性,就需要谨慎对待了。另外,由于内存的基本单位是字节,而位域只是字节的一部分,所以并不能对位域进行取地址运算。

[color=rgba(127, 194, 194, 0.498)]❞

虽然科技发展日新月异,但是秉承着节约成本这个放之四海而皆准的原则,还是要注意使用!毕竟5毛钱可能是小钱,但是乘以5000万呢?

版权归原作者所有,如有侵权,请联系删除。


onlycook 发表于 2022-5-7 08:57 来自手机 | 显示全部楼层
楼主分享的笔记真不错,全面详细
saservice 发表于 2022-6-7 08:52 | 显示全部楼层
结构体和共同体的区别是什么?
macpherson 发表于 2022-6-7 17:04 | 显示全部楼层
C语言 结构体定义
nomomy 发表于 2022-6-7 18:33 | 显示全部楼层
c语言中结构体怎么写
onlycook 发表于 2022-6-8 10:00 来自手机 | 显示全部楼层
非常感谢楼主的辛苦码字分享
quickman 发表于 2022-6-21 20:13 | 显示全部楼层
定义结构体的几种方法  
andygirl 发表于 2022-6-21 20:40 | 显示全部楼层
怎么看着想考试题
robertesth 发表于 2022-6-21 20:59 | 显示全部楼层
结构体Struct怎么使用?
Uriah 发表于 2022-10-6 13:14 | 显示全部楼层

通常选择0.01μF~0.1μF的陶瓷电容作为旁路电容。
Bblythe 发表于 2022-10-6 16:13 | 显示全部楼层

防止因瞬间大电流引起的电源电压下降
Pulitzer 发表于 2022-10-6 19:12 | 显示全部楼层

与15号引脚连接的C1称为旁路电容
周半梅 发表于 2023-5-1 07:16 | 显示全部楼层

I2C1工作时钟源选择;I2C1模块工作时钟的开启使能。
童雨竹 发表于 2023-5-1 08:09 | 显示全部楼层

通过访问寄存器来控制I2C1工作时钟的开启。
Wordsworth 发表于 2023-5-1 09:12 | 显示全部楼层

I2C1的时钟可以自行选择HSI或者SYSCLK
Clyde011 发表于 2023-5-1 10:15 | 显示全部楼层

CPU借助于APB总线访问相关寄存器达到对I2C1工作模块的控制
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部