【STM32学习过程】C语言中的宏定义(#define)

本文介绍了C语言中的宏定义,包括无参宏、#define与typedef的区别、有参宏以及#运算符、##运算符的使用。强调了宏定义的作用域、文本替换特性以及宏定义在简化常量管理和代码理解上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍宏定义(#define)

1.概念及无参宏

一个最简单的宏的形式如下:

#define    宏名   替换文本

        每个#define行(即逻辑行)由三部分组成:

        第一部分是指令 #define 自身,“#”表示这是一条预处理命令,“define”为宏命令。

        第二部分为宏(macro),一般为缩略语,其名称(宏名)一般大写,而且不能有空格,遵循C变量命令规则。“替换文本”可以是任意常数、表达式、字符串等。

        在预处理工作过程中,代码中所有出现的“宏名”,都会被“替换文本”替换。这个替换的过程被称为“宏代换”或“宏展开”(macro expansion)。“宏代换”是由预处理程序自动完成的。在C语言中,“宏”分为两种:无参数和有参数

1.1 无参宏

无参宏:指宏名之后不带参数,上面最简单的宏就是无参宏。

#define M 5                // 宏定义
#define PI 3.14            //宏定义
int a[M];                  // 会被替换为: int a[5];
int b = M;                 // 会被替换为: int b = 5;
printf("PI = %.2f\n", PI); // 输出结果为: PI = 3.14

注意①:宏不是语句,结尾不需要加“;”,否则会被替换进程序中,如: 

#define N 10;               // 宏定义
int c[N];                   // 会被替换为: int c[10;]; 
//error:… main.c:133:11: Expected ']'

以上几个宏都是用来代表值,所以被成为类对象宏(object-like macro,还有类函数宏,下面会介绍)。 

注意②:如果要写宏不止一行,则在结尾加反斜线符号使得多行能连接上,如:

#define HELLO "hello \
the world"

 注意第二行要对齐,否则,如:

#define HELLO "hello the wo\
  rld"
printf("HELLO is %s\n", HELLO);
//输出结果为: HELLO is hello the wo  rld 

 也就是行与行之间的空格也会被作为替换文本的一部分

而且由这个例子也可以看出:宏名如果出现在源程序中的“”内,则不会被当做宏来进行宏代换。

 注意③:宏可以嵌套,但不参与运算:

#define M 5                 // 宏定义
#define MM M * M            // 宏的嵌套
printf("MM = %d\n", MM);    // MM 被替换为: MM = M * M, 然后又变成 MM = 5 * 5

宏代换的过程在上句已经结束,实际的 5 * 5 相乘过程则在编译阶段完成,而不是在预处理器工作阶段完成,所以宏不进行运算,它只是按照指令进行文字的替换操作。

再强调下,宏进行简单的文本替换,无论替换文本中是常数、表达式或者字符串等,预处理程序都不做任何检查,如果出现错误,只能是被宏代换之后的程序在编译阶段发现。

注意④:宏定义的位置

        宏定义必须写在函数之外,其作用域是 #define 开始,到源程序结束。如果要提前结束它的作用域则用 #undef 命令,如:

#define M 5                 // 宏定义
printf("M = %d\n", M);      // 输出结果为: M = 5
#define M 100               // 取消宏定义
printf("M = %d\n", M);      // error:… main.c:138:24: Use of undeclared identifier 'M'

 注意⑤:可以用宏定义表示数据类型,可以使代码简便:

#define STU struct Student      // 宏定义STU
struct Student{                 // 定义结构体Student
    char *name;
    int sNo;
};
STU stu = {"Jack", 20};         // 被替换为:struct Student stu = {"Jack", 20};
printf("name: %s, sNo: %d\n", stu.name, stu.sNo);

注意⑥: 重复定义宏

        如果重复定义宏,则不同的编译器采用不同的重定义策略。有的编译器认为这是错误的,有的则只是提示警告。

注意总结:这些简单的宏主要被用来定义那些显式常量,而且会使得程序更加容易修改,特别是某一常量的值在程序中多次被用到的时候,只需要改动一个宏定义,则程序中所有出现该变量的值都可以被改变。而且宏定义还有更多其他优点,如使得程序更容易理解,可以控制条件编译等。

1.2 #define 与 #typedef 的区别

两者都可以用来表示数据类型,如:

#define INT1 int
typedef int INT2;

两者是等效的,调用也一样:

INT1 a1 = 3;
INT2 a2 = 5;

但当如下使用时,问题就来了:

#define INT1 int *
typedef int * INT2;
INT1 a1, b1;
INT2 a2, b2;
b1 = &m;         //... main.c:185:8: Incompatible pointer to integer conversion assigning to 'int' from 'int *'; remove &
b2 = &n;         // OK

因为 INT1 a1, b1; 被宏代换后为: int * a1, b1;即定义的是一个指向int型变量的指针 a1 和一个int型的变量b1.而INT2 a2, b2;表示定义的是两个变量a2和b2,这两个变量的类型都是INT2的,也就是int *的,所以两个都是指向int型变量的指针。

所以两者区别在于,宏定义只是简单的字符串代换,在预处理阶段完成。而typede不是简单的字符串代换,而是可以用来做类型说明符的重命名的,类型的别名可以具有类型定义说明的功能,在编译阶段完成的。

1.3 有参宏

C语言中宏是可以有参数的,这样的宏就成了外形与函数相似的类函数宏。
有参宏格式:

# define MEAN(X,Y)  (((X)+(Y))/2)

其中MEAN(X,Y) :宏名, (((X)+(Y))/2):替换文本,x、y:宏的参数。

宏调用:宏名(实参表)

printf(“MEAN = %d\n”, MEAN(7, 9)); // 输出结果: MEAN = 8

和函数类似,在宏定义中的参数成为形式参数,在宏调用中的参数成为实际参数。

1.4 #运算符、##运算符、可变宏

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值