打印
[应用方案]

了解嵌入式 C:什么是结构?

[复制链接]
2065|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
everyrobin|  楼主 | 2024-4-22 20:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本文提供了有关嵌入式 C 编程中的结构的一些基本信息。

结构
可以将多个在逻辑上相互关联的相同类型的变量分组为一个数组。处理一组而不是独立变量的集合使我们能够更方便地安排和使用数据。例如,我们可以定义以下数组来存储数字化语音输入的 ADC 的最后 50 个样本:

uint16_t voice[50];
请注意,uint16_t是一个无符号整数类型,宽度恰好为 16 位。这是在 C 标准库stdint.h中定义的,它提供独立于系统规范的特定位长度的数据类型。

数组可用于对多个具有相同数据类型的变量进行分组。如果不同数据类型的变量之间存在联系怎么办?我们可以在我们的程序中将这些变量视为一个组吗?例如,假设我们需要指定生成上述语音 数组的ADC的采样率。我们可以定义一个浮点变量来存储采样率:

float sample_rate;
尽管变量voice 和sample_rate 彼此相关,但它们被定义为两个独立变量。为了将这两个变量相互关联,我们可以使用 C 语言中一种强大的数据结构,称为结构。结构允许我们将不同的数据类型分组并将它们作为单个数据对象处理。结构可以包含不同种类的变量类型,例如其他结构、函数指针、结构指针等。对于语音示例,我们可以使用以下结构:

struct record {
    uint16_t voice[50];
    float sample_rate;
};
在这种情况下,我们有一个名为record的结构 ,它有两个不同的成员或字段:第一个成员是一个uint16_t元素数组,第二个成员是一个 float 类型的变量。语法以关键字struct开头。struct 关键字后面的词是一个可选名称,用于稍后引用该结构。我们将在本文的其余部分讨论定义和使用结构的其他细节。

为什么结构很重要?
上面的例子指出了结构的一个重要应用,即定义应用相关的数据对象,这些数据对象可以将不同类型的个体变量相互关联起来。这不仅导致了一种处理数据的有效方式,而且还允许我们实现称为数据结构的专用结构。

数据结构可用于各种应用程序,例如两个嵌入式系统之间的消息传递以及将从传感器收集的数据存储在非连续的内存位置。

图1.结构可用于实现链表。.png

此外,当程序需要访问内存映射微控制器外设的寄存器时,结构是有用的数据对象。我们将在下一篇文章中介绍结构应用程序。

图2.STM32MCU的内存映射。图片由ARM嵌入式系统提供。.png

声明结构
要使用结构,我们首先需要指定一个结构模板。考虑下面的示例代码:

struct record {
    uint16_t voice[4];
    float sample_rate;
};
这指定了用于创建此类未来变量的布局或模板。这个模板包括一个uint16_t数组和一个float类型的变量。模板的名称是 record ,它位于关键字struct之后。值得一提的是,没有用于存储结构模板的内存分配。内存分配仅在定义基于此布局的结构变量之后发生。以下代码声明 了上述模板的变量mic1 :

struct record mic1;
现在,为变量mic1分配了一段内存。它有空间存储数组的四个uint16_t元素和一个浮点变量。

可以使用成员运算符 (.) 访问结构的成员。例如,以下代码将 100 分配给数组的第一个元素,并将sample_rate的值复制到fs变量(必须是 float 类型)。

mic1.voice[0]=100;
fs=mic1.sample_rate;
声明结构的其他方法
我们在上一节中研究了一种声明结构的方法。C 语言支持一些其他格式,将在本节中进行回顾。您可能会在整个程序中坚持使用一种格式,但熟悉其他格式有时会有所帮助。

声明结构模板的一般语法是:

struct tag_name {
    type_1  member_1;
    type_2  member_2;
    …
    type_n  member_n;

} variable_name;
tag_name*和**variable_name*是可选 的 标识符。我们通常会至少看到这两个标识符中的一个,但在某些情况下我们可以同时消除它们。

语法 1: 当tag_name 和variable_name 都存在时,我们将在模板之后定义结构变量。使用这个语法,我们可以重写前面的例子如下:

struct record {
    uint16_t    voice[4];
    float       sample_rate;
} mic1;
现在,如果我们需要定义另一个变量( mic2 ),我们可以写

struct record mic2;
语法 2: 仅包含variable_name  。使用此语法,我们可以将上一节中的示例重写如下:

struct {
    uint16_t    voice[4];
    float       sample_rate;
} mic1;
在这种情况下,我们必须在模板之后定义所有变量,并且我们不能在程序中稍后定义任何其他变量(因为模板没有名称,我们以后不能引用它)。

语法 3: 在这种情况下,没有tag_name 或 variable_name 。以这种方式定义的结构模板称为匿名结构。可以在另一个结构或联合内定义匿名结构。下面给出一个例子:

struct test {
// Anonymous structure
    struct {
          float f;
          char a;
    };
} test_var;
要访问上述匿名结构的成员,我们可以使用成员运算符(.)。以下代码将 1.2 分配给成员 f 。

test_var.f=1.2;
由于结构是匿名的,我们只使用成员运算符访问它的成员一次。如果它有一个如下例所示的名称,我们将不得不使用成员运算符两次:

struct test {
         struct {
              float f;
              char a;
         } nested;
} test_var;
在这种情况下,我们应该使用以下代码将 1.2 分配给 f :

test_var.nested.f=1.2;
如您所见,匿名结构可以使代码更易读且更简洁。还可以使用 typedef 关键字和结构来定义新的数据类型。我们将在以后的文章中介绍这种方法。

结构的内存布局
C 标准保证结构的成员将按照成员在结构中声明的顺序一个接一个地位于内存中。第一个成员的内存地址将与结构本身的地址相同。考虑以下示例:

struct Test2{
    uint8_t     c;
        uint32_t    d;
        uint8_t     e;
    uint16_t    f;
} MyStruct;
将分配四个内存位置来存储变量 c、d、e 和 f。内存位置的顺序将与声明成员的顺序相匹配:c 的位置将具有最低地址,然后是 d、e,最后是 f。我们需要多少字节来存储这个结构?考虑到变量的大小,我们知道至少需要1+4+1+2=8个字节来存储这个结构。然而,如果我们为 32 位机器编译这段代码,我们会惊讶地发现MyStruct的大小是 12 个字节而不是 8 个!这是因为编译器在为结构的不同成员分配内存时具有某些限制。例如,一个 32 位整数只能存储在地址可以被 4 整除的内存位置。实施此类约束(称为数据对齐要求)是为了让处理器更有效地访问变量。数据对齐会导致内存布局中的一些空间浪费(或填充)。

图3.数据对齐导致内存布局中的一些空间浪费(或填充)。.png

了解数据对齐要求后,我们可以重新排列结构中成员的顺序并提高内存使用效率。例如,如果我们重写上面的结构如下所示,它的大小在 32 位机器上将减少到 8 个字节。

struct Test2{
        uint32_t    d;
    uint16_t    f;
    uint8_t     c;  
        uint8_t     e;
} MyStruct;
对于内存受限的嵌入式系统,将数据对象的大小从 12 字节减少到 8 字节是一个显着的节省,特别是当程序需要许多这样的数据对象时。

概括
结构允许我们定义依赖于应用程序的数据对象,这些数据对象可以将不同类型的各个变量相互关联。这导致了一种处理数据的有效方法。
称为数据结构的专用结构可用于各种应用程序,例如两个嵌入式系统之间的消息传递以及将从传感器收集的数据存储在不连续的内存位置。
当我们需要访问内存映射微控制器外围设备的寄存器时,结构很有用。
我们可以通过重新排列结构中成员的顺序来提高内存使用效率。

使用特权

评论回复
沙发
maudlu| | 2024-5-1 20:59 | 只看该作者
在嵌入式C语言中,**结构(struct)**是一种用户定义的数据类型,它允许你将不同类型的数据项组合成一个单一的类型。结构可以包含多个成员,每个成员可以是不同的数据类型,如整数、浮点数、字符等。

使用特权

评论回复
板凳
adolphcocker| | 2024-5-7 12:36 | 只看该作者
结构体在C语言中是通过关键字struct来定义的,它允许你创建自定义的数据类型,这些数据类型可以包含多种基本数据类型,如整数、浮点数、字符等,也可以包含其他结构体类型,形成嵌套结构。结构体中的各个成员变量通过名称来区分,并且可以通过点运算符(.)来访问结构体中的各个成员。

使用特权

评论回复
地板
jonas222| | 2024-5-7 12:45 | 只看该作者
结构的定义使用struct关键字,后跟结构名称和大括号内的成员列表。例如:

struct Point {
    int x;
    int y;
};

使用特权

评论回复
5
pentruman| | 2024-5-7 18:14 | 只看该作者
Student就是一个结构体类型,它包含了三个成员变量:name、age和score。之后我们就可以创建Student类型的变量,并为其成员赋值。

使用特权

评论回复
6
lzmm| | 2024-5-8 13:00 | 只看该作者
C语言无法直接操作数据库,所以在项目中,我们常常通过对结构体内部变量的操作,将大量的数据存储在内存中,以完成对数据的存储和操作。

使用特权

评论回复
7
xiaoyaodz| | 2024-5-8 21:18 | 只看该作者
在嵌入式系统中,结构常常被用来封装一些相关的属性或数据,以便更方便地管理和操作这些数据。

使用特权

评论回复
8
robertesth| | 2024-5-8 21:44 | 只看该作者
在嵌入式系统中,结构体经常用来定义设备的配置结构、数据包的格式、传感器的读数等等。由于内存资源有限,合理地使用结构体可以有效地管理和访问相关的数据,这对于优化内存使用是非常重要的。

使用特权

评论回复
9
everyrobin|  楼主 | 2024-5-9 12:59 | 只看该作者
结构是嵌入式C语言中一种非常有用的数据类型

使用特权

评论回复
10
uptown| | 2024-5-9 14:00 | 只看该作者
在C语言中,结构(struct)是一种自定义的数据类型,它允许将多个不同类型的数据组合在一起,形成一个新的数据类型。

使用特权

评论回复
11
beacherblack| | 2024-5-9 14:43 | 只看该作者
结构也可以使用指针进行操作。要获取结构变量的地址,可以使用&运算符。

使用特权

评论回复
12
wengh2016| | 2024-5-9 15:38 | 只看该作者
处理嵌套结构体或者包含对齐要求较高的数据类型(如long long int,在某些平台上可能要求8字节对齐)时尤其重要。

使用特权

评论回复
13
mollylawrence| | 2024-5-9 16:38 | 只看该作者
结构的定义通常使用struct关键字,后面跟着结构名,然后是一个大括号,其中包含结构的成员列表。每个成员都需要指定其数据类型和名称。

使用特权

评论回复
14
plsbackup| | 2024-5-9 19:06 | 只看该作者
在嵌入式C编程中,结构(struct)是一种复合数据类型,它允许将一组相关的变量(可能是不同类型的)组织在一起。结构体内的成员可以是各种不同的数据类型,包括其他结构体,这使得结构体可以用来表示比较复杂的数据结构。

使用特权

评论回复
15
mikewalpole| | 2024-5-10 10:48 | 只看该作者
在嵌入式C语言中,结构(struct)是一种复合数据类型,它允许程序员将不同类型的数据组合在一起形成一个单一的实体。这种数据结构类似于其他高级编程语言中的记录或对象,使得相关的数据能够作为一个整体被引用和处理。

使用特权

评论回复
16
modesty3jonah| | 2024-5-10 16:41 | 只看该作者
结构在嵌入式编程中有很多应用,例如:

表示复杂的数据结构,如链表、树等。
将相关的数据组合在一起,提高代码的可读性和可维护性。
通过结构指针传递数据,减少内存占用和提高性能。

使用特权

评论回复
17
benjaminka| | 2024-5-10 19:06 | 只看该作者
在嵌入式编程中,结构的使用非常普遍

使用特权

评论回复
18
mollylawrence| | 2024-5-12 10:16 | 只看该作者
C语言中,结构体的成员默认按照它们被声明的顺序依次存储在内存中,每个成员的起始地址是其前一个成员的结束地址。

使用特权

评论回复
19
gouguoccc| | 2024-5-12 11:06 | 只看该作者
用C语言把数据结构和链表玩熟练

使用特权

评论回复
20
jkl21| | 2024-5-12 14:04 | 只看该作者
提高代码的可读性和可维护性。              

使用特权

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

本版积分规则

15

主题

1337

帖子

0

粉丝