嵌入式C语言阶段复习——核心基础

一、宏定义(#define)

宏定义是预处理指令,用来给常量、表达式或代码片段起别名,预处理阶段会直接替换文本

复制代码
1、常量宏
#define PI 3.1415926
#define MAX_NUM 100

2. 带参数的宏
#define ADD(a, b) ((a) + (b))  // 加括号避免优先级问题
#define SQUARE(x) ((x) * (x))

宏替换是 "文本替换 ",比如 SQUARE(3+2) 会变成 (3+2)*(3+2)(加括号才正确,否则会变成 3+2*3+2

宏替换无类型检查,可能会导致出错(比如传非数值类型)

注意结尾不要加分号,否则会导致替换出来的值报错

二、结构体(struct)

结构体用来封装不同类型的数据(比如一个学生的姓名、年龄、成绩)

复制代码
1、定义结构体类型
struct Student {
    char name[20];  // 姓名
    int age;        // 年龄
    float score;    // 成绩
};

2、定义结构体变量并初始化
struct Student stu1 = {"张三",19,60.5};

3. 访问结构体成员(用.操作符)
printf("姓名:%s,年龄:%d,成绩:%.1f\n", stu1.name, stu1.age, stu1.score);
    
4. 修改成员
strcpy(stu1.name, "李四");  // 字符串赋值用strcpy,不能直接stu1.name="李四"
stu1.score = 98.0;
printf("修改后:%s,%d,%.1f\n", stu1.name, stu1.age, stu1.score);
    
5. 结构体指针(用->操作符)
struct Student *p = &stu1;
printf("通过指针访问:%s,%d\n", p->name, p->age);

结构体类型是(struct 结构体名),比如(struct Student),不能省略struct

结构体占用的内存是成员变量的内存之和(可能有内存对齐,比如 char [20]+int+float 通常占 28 字节)

结构体可以嵌套使用

三、共用体(union)

共用体和结构体用法类似,不同在于共用体是共享内存

复制代码
1、定义共用体
union Data {
    int i;
    float f;
    char c;
};

union Data d;
printf("共用体大小:%zu 字节\n", sizeof(d));  // 输出4(取最大成员float的大小)
    
2、赋值int成员
    d.i = 100;
    printf("d.i = %d\n", d.i);  // 输出100
    // 此时访问f/c会是乱码(内存被覆盖)
    printf("d.f = %f\n", d.f);  // 输出无意义的浮点数
    
3、赋值float成员(覆盖之前的int内存)
    d.f = 3.14f;
    printf("d.f = %.2f\n", d.f);  // 输出3.14
    printf("d.i = %d\n", d.i);    // 输出浮点数3.14对应的整数编码(乱码)

共用体大小 = 最大成员的大小

常用于 "异构数据" 场景(比如存储不同类型但不同时使用的数据),或解析二进制数据(比如拆分整型的字节)。

四、typedef

typedef 用来给已有类型起 "别名",简化复杂类型的书写(比如结构体、指针、数组)

cs 复制代码
1、给基本类型起别名
typedef int MyInt;
typedef float Score;

2、给结构体起别名(最常用)
typedef struct {  // 匿名结构体+typedef,直接定义别名
    char name[20];
    int age;
} Student;  // 别名是Student,无需写struct Student

3、给指针类型起别名
typedef int* IntPtr;

    MyInt a = 10;  // 等价于int a=10
    Score s = 95.5;  // 等价于float s=95.5
    
    Student stu = {"王五", 20};  // 直接用Student,不用struct
    printf("姓名:%s,年龄:%d\n", stu.name, stu.age);
    
    IntPtr p = &a;  // 等价于int *p=&a
    printf("*p = %d\n", *p);  // 输出10

typedef不创建新类型,只是给现有类型起别名

对比 #define:typedef 有类型检查,#define 只是文本替换

五、枚举(enum)

枚举用来定义一组有名字的常量(比如星期、颜色、状态码),增强代码可读性

cs 复制代码
1、定义枚举类型(默认从0开始,依次+1)
enum Week {
    MON,  // 0
    TUE,  // 1
    WED,  // 2
    THU,  // 3
    FRI,  // 4
    SAT,  // 5
    SUN   // 6
};

2、自定义枚举值
enum Color {
    RED = 1,
    GREEN = 3,
    BLUE = 5
};

    enum Week today = WED;
    printf("今天是周%d\n", today);  // 输出2
    
    enum Color c = GREEN;
    printf("绿色的枚举值:%d\n", c);  // 输出3
    
    
    if (today == 2)    // 枚举本质是整型,可以赋值/比较
    {                     
        printf("今天是周三\n");
    }

枚举常量是整型,可直接用整数赋值(但不建议,失去枚举的意义)

常用于替代魔法数字(比如用SUCCESS=0ERROR=1 代替直接写 0/1)

六、位操作

位操作直接操作二进制位,效率极高,常用于硬件控制、数据压缩、权限管理等场景。核心运算符:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)

cs 复制代码
int a = 6;   // 二进制:0110
int b = 3;   // 二进制:0011
    
1、按位与(对应位都为1才为1)
printf("a&b = %d\n", a & b);  // 0010 → 2
    
2、按位或(对应位有一个1就为1)
printf("a|b = %d\n", a | b);  // 0111 → 7
    
3、按位异或(对应位不同为1)
printf("a^b = %d\n", a ^ b);  // 0101 → 5
    
4、按位取反(所有位取反,包括符号位)
printf("~a = %d\n", ~a);      // 补码运算,结果为-7
    
5、左移(乘以2^n)
printf("a<<1 = %d\n", a << 1);  // 1100 → 12
    
6、右移(除以2^n,符号位不变)
printf("a>>1 = %d\n", a >> 1);  // 0011 → 3

位操作只适用于整型(char、short、int、long)

左移 / 右移不要超出类型的位数(比如 int 是 32 位,左移 32 位未定义)

无符号数右移补 0,有符号数右移补符号位(正数补 0,负数补 1)

七、malloc(动态内存分配)

malloc 用来在堆区动态分配内存,使用后必须用free释放,否则内存泄漏

cs 复制代码
    1、分配单个int的内存
    int *p1 = (int*)malloc(sizeof(int));
    if (p1 == NULL) {  // 必须检查是否分配成功(内存不足时返回NULL)
        perror("malloc failed");
        return 1;
    }
    *p1 = 100;
    printf("*p1 = %d\n", *p1);
    
    2、分配数组内存(5个int)
    int *arr = (int*)malloc(5 * sizeof(int));
    if (arr == NULL) {
        perror("malloc arr failed");
        free(p1);  // 先释放已分配的内存
        return 1;
    }
    // 赋值并遍历
    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;
        printf("%d ", arr[i]);  // 输出1 2 3 4 5
    }
    printf("\n");
    
    3、分配结构体内存
    typedef struct {
        char name[20];
        int age;
    } Stu;
    Stu *stu = (Stu*)malloc(sizeof(Stu));
    if (stu == NULL) {
        perror("malloc stu failed");
        free(p1);
        free(arr);
        return 1;
    }
    strcpy(stu->name, "赵六");
    stu->age = 22;
    printf("姓名:%s,年龄:%d\n", stu->name, stu->age);
    
    4、释放内存(必须释放,且只释放一次)
    free(p1);
    free(arr);
    free(stu);

    // 释放后指针置NULL,避免野指针
    p1 = NULL;
    arr = NULL;
    stu = NULL;

malloc(size):参数是要分配的字节数,返回void*需强制类型转换

分配失败返回NULL,必须检查,否则会导致段错误

内存泄漏:分配的内存未释放,程序结束前一直占用堆空间(长期运行的程序会耗光内存)

相关推荐
ZHOUPUYU6 小时前
PHP 8.3网关优化:我用JIT将QPS提升300%的真实踩坑录
开发语言·php
寻寻觅觅☆10 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
YJlio10 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
l1t11 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿11 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar12312 小时前
C++使用format
开发语言·c++·算法
码说AI12 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS12 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
星空下的月光影子12 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言
老约家的可汗12 小时前
初识C++
开发语言·c++