一、enum(枚举)
enum
是 C 语言中的一种枚举类型(enumeration),用于定义一组具名的整型常量,增加代码的可读性和可维护性。
基本语法
enum 枚举名 {
枚举常量1,
枚举常量2,
...
};
默认从0
开始,依次加1
增:
enum Weekday {
MON, //0
TUE, //1
WED, //2
THU, //3
FRI, //4
SAT, //5
SUN //6
} today1; //可以在定义枚举类型的同时进行变量的定义
enum Weekday today2; //也可以单独定义变量
也可以手动赋值:
enum Color {
RED, // 0
GREEN = 5, // 5
BLUE // 6
};
enum Status {
OK = 0,
ERROR = 1,
UNKNOWN = -1
};
用法示例
#include <stdio.h>
enum Status {
OK = 0,
ERROR = 1,
UNKNOWN = -1
};
int main() {
enum Status s = OK;
switch(s){
case OK:
printf("Everything is fine.\n");
break;
case ERROR:
printf("Somthing is error.\n");
break;
case UNKNOWN:
printf("Somthing is unknown.\n");
break;
default:
break;
}
return 0;
}
二、struct(结构)
struct
是 C 语言中一种用户自定义的数据类型,可以将多个不同类型的变量组合成一个整体。适合用来描述一个实体,比如学生、员工、坐标等。
基本语法
struct 结构体名 {
类型1 成员名1; //成员类型可以是基础数据类型,也可以是数组、指针、结构体、函数指针等
类型2 成员名2;
...
};
同enum
一样,可以在定义struct
同时,定义变量,也可以单独定义变量
struct Point {
int x;
int y;
} p1, p2;
struct Point p3,p4;
用法示例
#include <stdio.h>
struct Student {
char name[50];
int age;
float score;
};
int main() {
struct Student s1 = {"Alice", 20, 95.5};
printf("Name: %s\n", s1.name);
printf("Age: %d\n", s1.age);
printf("Score: %.1f\n", s1.score);
return 0;
}
结构体数组
struct Student students[2] = {
{"Alice", 20, 95.5},
{.name = Bob",
.age = 21,
.score = 88.0}
};
指针与结构体
struct Student s = {"Charlie", 22, 90.0};
struct Student *p = &s;
printf("Name via pointer: %s\n", p->name); // 用 "->" 访问成员
三、bit-filed(位域)
C语言的位域(bit-field),一种可以精确控制变量中**每一位或几位**存储方式的结构体特性,常用于嵌入式、协议解析、寄存器映射等场景。
位域就是在结构体中,通过冒号指定成员所占的位数。
struct {
unsigned int a : 3; // a 占3位
unsigned int b : 5; // b 占5位
} data1;
struct {
unsigned int a; // a 占8字节
unsigned int b; // b 占8字节
} data2;
这表示 data1
总共只占用 8 位(1 字节),而不是两个完整的 unsigned int
(通常是 8 字节)。
基本语法
struct 结构体名 {
类型 成员名 : 位数;
};
类型通常是 int
, unsigned int
,但实际只取它的一部分位数。
位数决定该成员最多能表示的值范围(例如 3 位能表示 0~7)。
用法示例
#include <stdio.h>
struct Status {
unsigned int powerOn : 1; // bit 0
unsigned int error : 1; // bit 1
unsigned int mode : 2; // bits 2-3
unsigned int reserve : 4; // bits 4-7
};
int main() {
struct Status s = {1, 0, 2, 0};
printf("powerOn = %u\n", s.powerOn);
printf("error = %u\n", s.error);
printf("mode = %u\n", s.mode);
return 0;
}
注意事项
1.位域不能取地址(不能用 &s.mode
);
2.不同编译器对位域排列方式可能不同(大端/小端问题);
3.类型不能用 char
,推荐使用 unsigned int
;
4.通常会有字节对齐问题,结构体大小不一定是你位数总和,建议加 #pragma pack(1)
或 __attribute__((packed))
视平台而定。
备注:
#pragma pack(1)
和 __attribute__((packed))
使用、
C语言为了提高访问效率,会对结构体成员进行自动对齐(如按 4 字节、8 字节),可能会插入填充字节(padding)。
例如:
struct A {
char a; // 1字节
int b; // 4字节
};
这会占用 8字节(1字节char + 3字节padding + 4字节int),而不是5字节。
#pragma pack(1)
:编译器指令(Visual Studio/GCC兼容):
#pragma pack(1) // 结构体内成员按1字节对齐
struct A {
char a;
int b;
};
#pragma pack() // 恢复默认对齐
__attribute__((packed))
:GCC/Clang专用语法
struct __attribute__((packed)) A {
char a;
int b;
};
以上两种做法均可强制去掉结构体内的 padding。
四、union(联合)
union
(联合体)是一种特殊的结构体,它的所有成员共享同一块内存空间。也就是说,在同一时间,只能使用其中的一个成员。
基本语法
union 联合体名 {
数据类型1 成员1;
数据类型2 成员2;
...
};
用法示例
#include <stdio.h>
union Data {
int i;
float f;
char str[20];
};
int main() {
union Data data;
data.i = 10;
printf("data.i = %d\n", data.i);
data.f = 3.14;
printf("data.f = %.2f\n", data.f); // 这时 data.i 的值会被覆盖
return 0;
}
和 struct
的区别
union data3{
unsigned char a;
unsigned int b;
}
struct data4{
unsigned char a;
unsigned int b;
}
特性 | struct | union |
---|---|---|
内存分配 | 每个成员各占一块独立内存 | 所有成员共用同一块内存 |
总大小 | 所有成员大小之和(考虑对齐) | 最大的成员大小 |
同时存储多个值 | 是 | 否(只能存一个) |
应用场景 | 一组信息同时存在,比如学生信息 | 多种数据格式共存但不会同时使用 |
union Test {
int a; // 4字节
short b; // 2字节
char c; // 1字节
};
// union Test 的大小 = 4(最大成员大小)
实用场景
1.内存优化
在嵌入式系统/协议解析中,不同数据类型共用一段内存,可以节省空间。
2.类型转换(低层次实现)
比如浮点转整型等:
union {
float f;
int i;
} u;
u.f = 3.14;
printf("Float 3.14 as int: %d\n", u.i);
3.协议解析 / 寄存器映射
一个字段可能有多种解释方式,可以通过 union 提供多种视图。
注意事项
-
不能同时使用多个成员,因为它们共用内存;
-
不要依赖某个成员赋值后再访问另一个成员的值(除非你明确知道内存布局);
-
union
和struct
可以嵌套使用。
五、typedef
typedef
是 C 语言中常用的关键字,用于给已有类型定义一个新的别名,让代码更简洁、更易读。
基本语法
typedef 原类型 新名字;
简单示例
//结构体示例
typedef struct {
char name[20];
int age;
} Person;
Person p1; // 不需要再写 struct 了,代码更简洁
//基本类型示例
typedef unsigned int uint;
uint age = 25; // 等价于 unsigned int age = 25;
//函数指针示例
typedef int (*Operation)(int, int);
int add(int a, int b) { return a + b; }
Operation op = add;
int result = op(2, 3); // 调用函数指针
typedef 和 #define 区别
对比点 | typedef | #define |
---|---|---|
是否检查类型 | 编译器识别类型 | 预处理阶段替换 |
是否调试友好 | 能查看类型信息 | 只是文本替换 |
建议用途 | 建议用于定义类型别名 | 建议用于宏常量定义 |
总结
-
typedef
可以让结构体、函数指针、数组等复杂类型更简洁; -
常用于提升可读性和跨平台移植性(比如
uint32_t
就是 typedef 的); -
与
struct
一起用最常见。