[开发资料] 单片机的预处理

[复制链接]
449|35
jf101 发表于 2025-10-21 13:47 | 显示全部楼层 |阅读模式
预处理命令可以改变程序设计环境,提高编程效率,它们并不是C语言本身的组成部分,不能直接对它们进行编译,
必须在对程序进行编译之前,先对程序中这些特殊的命令进行“预处理”。经过预处理后,程序就不再包括预处理命令了,
最后再由编译程序对预处理之后的源程序进行编译处理,得到可供执行的目标代码。C语言提供的预处理功能有三种,
分别为宏定义、文件包含和条件编译,下面将对它们进行简单介绍。


 楼主| jf101 发表于 2025-10-21 13:49 | 显示全部楼层
1、宏定义 #define
宏定义在C语言源程序中允许用一个标识符来表示一个字符串,称为“宏”,被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的。在C语言中,宏分为有参数和无参数两种。

无参宏的宏名后不带参数,其定义的一般形式为:#define 标识符 字符串; ,“字符串”可以是常数、表达式、格式串等。

常常对程序中反复使用的表达式进行宏定义。例如:

  1. #define M (y*y+3*y);


它的作用是指定标识符M来代替表达式(yy+3y)。在编写源程序时,所有的(yy+3y)都可由M代替,而对源程序进行编译时,将先由预处理程序进行宏代换,即用(yy+3y)表达式去置换所有的宏名M,然后再进行编译。

C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对于带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

带参宏定义的一般形式为:#define 宏名(形参表) 字符串;

带参宏调用的一般形式为:宏名(实参表);

举例:

  1. #include <stdio.h>
  2. #define MAX(a,b) (a>b)?a:b
  3. /*带参数的宏定义*/
  4. main()
  5. {
  6.     int x,y,max;
  7.     printf("input two numbers: ");
  8.     scanf("%d %d",&x,&y);
  9.     max=MAX(x,y);
  10.     printf("max=%d\n",max);
  11.     /*宏调用*/
  12. }


结果如下:

  1. input two numbers: 2009 2010↙
  2. max=2010


可以看到,宏替换相当于实现了一个函数调用的功能,而事实上,与函数调用相比,宏调用更能提高C程序的执行效率。

#define 后面只有一个参数的语法:
一般情况下,宏定义时的用法为:#define a b ,后接两个参数,表示用a代替b。很多时候,#define 后只有一个参数,经常出现在头文件的开始处。

用法解释: 定义宏,并在预处理过程中将其替换为空字符串(即删除)。这样做主要是为了标记某些内容,使程序阅读者能够清楚标记表明的意义,同时又不影响被编译的源代码。也就是说,用法同define后接两个参数一样,只是后一个参数为空字符串。
用途包括:(1)定义一个符号用来给#if(n)def判断。(2)多文件编译中防止头文件被重复包含。

 楼主| jf101 发表于 2025-10-21 13:50 | 显示全部楼层
文件包含 #include
文件包含是C预处理程序的另一个重要功能,文件包含命令行的一般形式为:

#include <文件名> :用尖括号包含头文件,在系统指定的路径下找头文件。

#include "文件名" :用双引号包含头文件,先在当前目录下找头文件,找不到,再到系统指定的路径下找。

注意:include 经常用来包含头文件,可以包含 .c 文件,但是大家不要包含.c。因为include 包含的文件会在预编译被展开,如果一个.c 被包含多次,展开多次,会导致函数重复定义。预处理只是对include 等预处理操作进行处理并不会进行语法检查,这个阶段有语法错误也不会报错,第二个阶段即编译阶段才进行语法检查。

一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。
 楼主| jf101 发表于 2025-10-21 13:51 | 显示全部楼层
3、条件编译
预处理程序提供了条件编译的功能,可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,这对于程序的移植和调试是很有用的。条件编译可分为三种形式。

(1)第一种形式如下:

  1. #ifdef 标识符
  2. 程序段 1
  3. #else
  4. 程序段 2
  5. #endif

它的功能是如果 标识符 已被 #define 命令定义过则对 程序段1 进行编译;否则对 程序段2 进行编译。

如果没有程序段2(为空),本格式中的#else可以没有,即可以写为:

  1. #ifdef 标识符
  2. 程序段
  3. #endif


(2)第二种形式如下:

  1. #ifndef 标识符
  2. 程序段 1
  3. #else
  4. 程序段 2
  5. #endif


与第一种形式的区别是将 “ifdef” 改为 “ifndef” 。它的功能是如果 标识符 未被 #define 命令定义过则对 程序段1 进行编译,否则对 程序段2 进行编译。这与第一种形式的功能正好相反。

(3)第三种形式如下:

  1. #if 常量表达式
  2. 程序段 1
  3. #else
  4. 程序段 2
  5. #endif

它的功能是如果常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因此可以使程序在不同的条件下完成不同的功能。

OKAKAKO 发表于 2025-10-22 20:40 | 显示全部楼层
文件包含是C预处理程序的另一个重要功能
AdaMaYun 发表于 2025-10-23 15:01 | 显示全部楼层
预处理其实是很关键的过程
中国龙芯CDX 发表于 2025-10-24 14:11 | 显示全部楼层
其实大多数程序的基础用法很关键
nomomy 发表于 2025-11-3 22:12 | 显示全部楼层
无论是使用标准库、HAL库还是LL库,都需要包含相应的头文件来使用库函数。
ulystronglll 发表于 2025-11-5 13:16 | 显示全部楼层
在单片机开发中,宏定义无处不在,它让硬邦邦的寄存器操作和配置变得灵活和易读。
timfordlare 发表于 2025-11-5 21:07 | 显示全部楼层
显著提升了代码的可维护性、跨平台适配能力和开发效率。
febgxu 发表于 2025-11-8 11:33 | 显示全部楼层
预处理命令通过宏定义、文件包含和条件编译三大核心功能
xiaoyaodz 发表于 2025-11-8 14:34 | 显示全部楼层
条件编译是预处理在单片机开发中最强大、最核心的应用,它让同一份代码能够适配不同的硬件、实现不同的功能、区分不同的版本。
backlugin 发表于 2025-11-8 21:31 | 显示全部楼层
在大型项目中,通过头文件管理模块间的接口,避免代码重复。
hudi008 发表于 2025-11-9 07:56 | 显示全部楼层
单片机开发的核心是操作寄存器。直接操作寄存器地址
uytyu 发表于 2025-11-9 10:00 | 显示全部楼层
避免在宏中使用分号,防止替换后出现语法错误。
tifmill 发表于 2025-11-9 13:16 | 显示全部楼层
在单片机中,宏定义的应用尤为广泛。
bestwell 发表于 2025-11-9 19:33 | 显示全部楼层
条件编译允许你在编译时根据条件选择性地编译代码段。
updownq 发表于 2025-11-10 10:17 | 显示全部楼层
根据预定义标识符选择性编译代码段,常用指令包括#ifdef、#ifndef、#if等
everyrobin 发表于 2025-11-10 13:18 | 显示全部楼层
通过宏定义将特殊功能寄存器 映射为易读名称
bartonalfred 发表于 2025-11-10 16:20 | 显示全部楼层
宏定义不是真正的变量或函数,只是简单的文本替换。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

267

主题

2133

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部