《嵌入式C语言笔记(十三):预处理命令与指针基础全解析》

预处理命令

C程序编译流程:源文件 → 预处理(处理宏、头文件) → 编译 → 链接 → 可执行文件。

宏定义

不带参数的宏:

#define PI 3.1415926  // 定义常量
#define DEBUG_MODE   // 定义条件编译标志,为条件编译做准备工作

带参数的宏:

#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SQUARE(x) ((x) * (x))

陷阱与解决:参数需加括号,避免运算符优先级错误。

// 错误示例:
#define MUL(a, b) a * b
MUL(1+2, 3) → 1+2*3=7(预期9)

// 正确写法:
#define MUL(a, b) ((a) * (b))

带参数的宏比函数调用效率高,但更消耗内存。函数需要保护现场和恢复现场,宏直接展开,如果使用过多,会导致代码缺乏复用性。

文件包含处理

语法:

#include <stdio.h>   // 系统头文件
#include "my_lib.h"   // 用户自定义头文件

头文件保护:防止重复包含,避免多次定义。

// my_lib.h
#ifndef MY_LIB_H
#define MY_LIB_H
// 头文件内容
#endif

条件编译

常见指令:

#ifdef DEBUG
  printf("调试信息");
#endif

#if CPU_TYPE == ARM
  // ARM平台专用代码
#elif CPU_TYPE == X86
  // x86平台专用代码
#else
  #error "不支持的平台"
#endif

应用场景:跨平台代码适配和调试代码开关。

指针基础

指针变量是一种用于存储内存地址的数据类型。其定义方式为:基类型 * 指针变量名。其中,基类型表示指针所指向的数据类型,*在定义时作为类型说明符,而在运算时则作为指针运算符。

定义指针变量后,可以通过赋值或初始化来为其分配地址。

int *p;  // 定义一个指向int类型的指针变量p
int a = 10;
p = &a;  // 将变量a的地址赋值给指针p

通过*指针变量名可以间接访问指针所指向的内存地址中的值。

int b = *p;  // 将指针p所指向的值赋给变量b

在64位操作系统中,指针变量通常占用8个字节,而在32位操作系统中,指针变量占用4个字节。

指针的使用

指针可以通过被调函数修改主调函数中的变量值。

void modify(int *ptr) {
    *ptr = 20;  // 修改指针所指向的值
}

int main() {
    int x = 10;
    modify(&x);  // 传递x的地址
    printf("%d", x);  // 输出20
    return 0;
}

和&运算符可以相互抵消。例如,&x等价于x。

指针的注意事项

指针变量和其指向的内存地址必须明确,否则会导致未定义行为,这种指针称为野指针。野指针通常是由于指针未初始化或指向已释放的内存区域造成的。

int *wild_ptr;  // 未初始化的指针,野指针

指针的访问过程

指针的访问过程可以分为以下三个步骤:

  1. 根据指针变量的值去内存中定位。
  2. 从定位处开始向后偏移sizeof(基类型)个字节。
  3. 将偏移后的那部分内存空间当作是一个基类型来看。

例如,对于int p,假设p指向地址0x1000,则p会从0x1000开始,读取4个字节(假设int类型为4字节),并将其解释为一个int类型的值。

int *p = (int *)0x1000;
int value = *p;  // 从地址0x1000开始读取4个字节,并将其解释为int类型

开发技巧

宏的优缺点

优点:提高代码复用性,减少函数调用开销。 缺点:调试困难,易引发隐蔽错误。

条件编译调试
#define DEBUG 1
#if DEBUG  // 调试代码
#endif

头文件设计

仅包含必要的声明(函数原型、宏、extern变量)。 禁止在头文件中定义全局变量(易引发重复定义)。

总结

预处理命令:宏替换、文件包含、条件编译是代码优化的核心工具。 指针本质:通过地址直接操作内存,需谨慎避免野指针。 嵌入式注意:宏定义替代简单函数提升效率,指针操作需严格校验地址合法性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值