打印
[应用相关]

【转】嵌入式 C | 结构体完全笔记,收藏!

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
21
盗铃何须掩耳|  楼主 | 2022-5-6 17:04 | 只看该作者 回帖奖励 |倒序浏览


结构体的搭档

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


typedef struct date
{
    int year;
    int month;
    int day;
} DATE;//为了区分,一般用全大写

int main(void)
{
    DATE* date;
    ...
}
甚至还可以顺便给它的指针也定义一个别名:
typedef struct date
{
    int year;
    int month;
    int day;
} DATE, *PDATE;




使用特权

评论回复
22
盗铃何须掩耳|  楼主 | 2022-5-6 17:06 | 只看该作者
进阶

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

比如:

int (*ptr) [5];

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

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



使用特权

评论回复
23
盗铃何须掩耳|  楼主 | 2022-5-6 17:11 | 只看该作者
共用体

共用体也称联合体。


初始化

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

nion data
{
    int i;
    char ch;
    float f;
};

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


使用特权

评论回复
24
盗铃何须掩耳|  楼主 | 2022-5-6 17:17 | 只看该作者


枚举

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

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

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

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

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

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

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

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

//Example 06
#include <stdio.h>
#include <stdlib.h>

int main()
{

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

    enum  color favorite_color;

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

    //输出结果
    switch (favorite_color)
    {
    case red:
        printf("你喜欢的颜色是红色");
        break;
    case green:
        printf("你喜欢的颜色是绿色");
        break;
    case blue:
        printf("你喜欢的颜色是蓝色");
        break;
    default:
        printf("你没有选择你喜欢的颜色");
    }

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

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

//Example 07

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

int main()
{
    enum day
    {
        saturday,
        sunday,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday;

    int a = 1;
    enum day weekend;
    weekend = (enum day) a;  //使用强制类型转换
    //weekend = a; //错误
    printf("weekend:%d", weekend);
    return 0;
}

运行结果如下:

//Consequence 07
weekend:1



使用特权

评论回复
25
盗铃何须掩耳|  楼主 | 2022-5-6 17:19 | 只看该作者
位域

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

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

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

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

//Example 08
#include <stdio.h>

int main(void)
{
struct Test
{
  unsigned int a : 1;
  unsigned int b : 1;
  unsigned int c : 2;
} test;

test.a = 0;
test.b = 1;
test.c = 2;

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

return 0;
}

运行结果如下:

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

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

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

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

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

unsigned int a : 100;

那么就会报错:

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

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

struct Test
{
    unsigned int x : 1;
    unsigned int y : 2;
    unsigned int z : 3;
    unsigned int : 26;
};

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

[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万呢?

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


使用特权

评论回复
26
onlycook| | 2022-5-7 08:57 | 只看该作者
楼主分享的笔记真不错,全面详细

使用特权

评论回复
27
saservice| | 2022-6-7 08:52 | 只看该作者
结构体和共同体的区别是什么?

使用特权

评论回复
28
macpherson| | 2022-6-7 17:04 | 只看该作者
C语言 结构体定义

使用特权

评论回复
29
nomomy| | 2022-6-7 18:33 | 只看该作者
c语言中结构体怎么写

使用特权

评论回复
30
onlycook| | 2022-6-8 10:00 | 只看该作者
非常感谢楼主的辛苦码字分享

使用特权

评论回复
31
quickman| | 2022-6-21 20:13 | 只看该作者
定义结构体的几种方法  

使用特权

评论回复
32
andygirl| | 2022-6-21 20:40 | 只看该作者
怎么看着想考试题

使用特权

评论回复
33
robertesth| | 2022-6-21 20:59 | 只看该作者
结构体Struct怎么使用?

使用特权

评论回复
34
Uriah| | 2022-10-6 13:14 | 只看该作者

通常选择0.01μF~0.1μF的陶瓷电容作为旁路电容。

使用特权

评论回复
35
Bblythe| | 2022-10-6 16:13 | 只看该作者

防止因瞬间大电流引起的电源电压下降

使用特权

评论回复
36
Pulitzer| | 2022-10-6 19:12 | 只看该作者

与15号引脚连接的C1称为旁路电容

使用特权

评论回复
37
周半梅| | 2023-5-1 07:16 | 只看该作者

I2C1工作时钟源选择;I2C1模块工作时钟的开启使能。

使用特权

评论回复
38
童雨竹| | 2023-5-1 08:09 | 只看该作者

通过访问寄存器来控制I2C1工作时钟的开启。

使用特权

评论回复
39
Wordsworth| | 2023-5-1 09:12 | 只看该作者

I2C1的时钟可以自行选择HSI或者SYSCLK

使用特权

评论回复
40
Clyde011| | 2023-5-1 10:15 | 只看该作者

CPU借助于APB总线访问相关寄存器达到对I2C1工作模块的控制

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则