结构体是C语言中组织和管理相关数据的核心工具,尤其在嵌入式开发中,它对于定义硬件寄存器、封装协议帧或构建复杂数据结构至关重要。本文将系统性地讲解结构体的定义、使用技巧及其在嵌入式场景下的常见应用。
定义结构体变量
定义一个结构体,本质上是创建了一种新的复合数据类型。例如,我们可以定义一个表示人员信息的结构体:
struct string
{
char name[8];
int age;
char sex[2];
char depart[20];
float wage1, wage2, wage3, wage4, wage5;
}person;
这段代码定义了一个名为 string 的结构体类型,并同时声明了一个该类型的变量 person。
另一种常见的做法是将类型定义和变量声明分开,这样可以提高代码的清晰度和复用性:
struct string
{
char name[8];
int age;
char sex[2];
char depart[20];
float wage1, wage2, wage3, wage4, wage5;
};
struct string person; // 使用已定义的结构体类型来声明变量 person
如果需要声明多个同类型的变量,可以一次性完成:
struct string Liming, Liuqi, ...;
在某些情况下,特别是当结构体仅在一个局部范围内(如某个函数内部)使用时,可以省略结构体名,定义所谓的“无名结构体”:
struct
{
char name[8];
int age;
char sex[2];
char depart[20];
float wage1, wage2, wage3, wage4, wage5;
} Liming, Liuqi;
此时,变量 Liming 和 Liuqi 的类型就是这个无名结构体,无法在其他地方复用此类型声明新的变量。
结构体成员的获取与赋值
定义了结构体变量后,如何访问其内部的成员呢?访问方式遵循以下格式:
结构变量.成员名
我们可以将 结构变量.成员名 视为一个整体,其使用方式与普通变量无异。下面通过一个简单的例子来演示:
#include <stdio.h>
int main()
{
struct
{
char *name; //姓名
int age; //年龄
char group; //所在小组
} stu1;
//给结构体成员赋值
stu1.name = “Tom”;
stu1.age = 18;
stu1.group = ‘A’;
//读取结构体成员的值
printf(“%s的年龄是%d,在%c组\n”, stu1.name, stu1.age, stu1.group);
return 0;
}
对于C语言初学者而言,熟练运用指针是进阶的关键,这在处理结构体时同样重要。
结构体数组
当需要管理一组具有相同结构的数据时,结构体数组便派上了用场。例如,要存储一个班级40名学生的信息,可以这样定义:
struct
{
char name[8];
char sex[2];
int age;
char addr[40];
}student[40];
访问结构体数组成员,需要先指定数组元素,再访问其成员:
结构数组元素.成员名
例如:
student[0].name
student[30].age
结构体指针
使用指针操作结构体可以提升效率,尤其是在传递大型结构体给函数时。结构体指针的定义方式是在结构体变量名前加 * 操作符:
struct string
{
char name[8];
char sex[2];
int age;
char addr[40];
}*student;
结构体指针访问成员时,使用 -> 操作符,这与普通结构体变量使用 . 操作符不同:
结构体指针名->结构体成员
例如,为上面定义的 student 指针所指向的结构体成员赋值:
strcpy(student->name, “acket”); // student->name 等价于 (*student).name
student->age = 18;
关键点:在通过指针访问结构体之前,必须确保指针指向有效的内存区域。通常需要为结构体指针动态分配内存:
student = (struct string*)malloc(size of (struct string));
// size of (struct string) 用于自动获取该结构体类型占用的字节长度
malloc() 函数会分配一块大小为结构体长度的内存,并将其起始地址作为结构体指针返回。在嵌入式系统中,动态内存分配需谨慎使用,有时会采用静态或栈上分配来保证确定性。
位结构(位域)
位结构是一种特殊形式的结构体,用于精确控制每个成员占用的内存位数,常用于访问硬件寄存器或进行紧凑的数据打包。其定义形式如下:
struct 位结构名
{
数据类型 变量名: 整型常数;
数据类型 变量名: 整型常数;
}位结构变量;
其中,数据类型必须是 int(unsigned 或 signed),但当成员长度为1时,会被默认为 unsigned。整型常数表示该成员占用的二进制位数,范围是0~15。
看一个具体的例子,这个位结构描述了一个可能用于显示控制的字节:
struct
{
unsigned incon: 8; /* incon 占用低字节的0~7共8位 */
unsigned txcolor: 4; /* txcolor 占用高字节的0~3位共4位 */
unsigned bgcolor: 3; /* bgcolor 占用高字节的4~6位共3位 */
unsigned blink: 1; /* blink 占用高字节的第7位 */
}ch;
访问位结构成员的方式与普通结构体相同:
ch.bgcolor
位结构在嵌入式系统编程中非常实用。例如,可以定义一个包含状态标志的结构体:
struct info
{
char name[8];
int age;
struct address addr;
unsigned char state:1; // 状态标志,1位
unsigned char payyyy:1; // 工资发放标志,1位
}people;
这里,state 和 payyyy 各用1位来表示布尔状态,极大地节省了存储空间。
使用 typedef 定义结构体
typedef 关键字可以为现有的类型(包括结构体)创建一个新的别名,这能简化代码书写,增强可读性。
typedef struct person
{
int age ;
char *name;
char *sex;
}student;
student stu1; // 现在可以使用别名 `student` 来定义结构体变量了
在上面的例子中,typedef 为 struct person 创建了别名 student。之后,就可以像使用内置类型一样使用 student 来声明变量,无需再写 struct 关键字。
总结
结构体是C语言构建复杂数据模型的基石。从基础的定义与访问,到数组、指针的高效操作,再到位域的精打细算和 typedef 带来的代码优雅,掌握这些知识点对于进行嵌入式开发至关重要。希望本文的梳理能帮助你更扎实地理解并运用结构体,写出更清晰、更高效的C语言代码。如果想进一步探讨或查看更多技术干货,欢迎访问云栈社区。