系列文章目录



🥙前言

为什么学define?

点击这里,查看所有玩转指针专栏的文章!
点击这里,查看所有百问C语言栏的文章!


百问C语言第1问——彻底弄懂define用法-LMLPHP

🥪#define的用法

🍑1.#define常见用法

其常见的用法包括两种,分别是:

1)#define 宏名 宏值
2)#define 宏名(参数列表) 表达式 

🌳定义常量

使用 #define 可以定义常量,这些常量在编译时会被其值替换。

#define PI 3.14159

在代码中,任何出现 PI 的地方都会被替换为 3.14159

#define MAX 100            // 将 MAX 这个标识符和 100 这个数字关联起来
#define REG register       // 为 register 这个关键字,创建一个简短的名字REG
#define STR "test_string"  // 用 STR 这样一个名字来代替 test_string 这样一个字符串
 
int main()
{
	REG int a = MAX;       // 这里的 reg 被解释成 register关键字,MAX 被解释成 100
 
	printf("%d\n", a);
 
	printf("%s\n", STR);     
	return 0; 
}

百问C语言第1问——彻底弄懂define用法-LMLPHP

🌳定义宏函数(注意点)

使用 #define 可以定义常量,这些常量在编译时会被其值替换。

#define Add(a,b) a+b;

📝【注意】
在一般使用的时候是没有问题的,但是如果遇到如:c * Add(a,b) * d的时候就会出现问题,代数式的本意是a+b然后去和c,d相乘,但是因为使用了define(它只是一个简单的替换),所以式子实际上变成了ca + bd

#define MAX(a, b) ((a) > (b) ? (a) : (b))

在代码中,任何出现 PI 的地方都会被替换为 3.14159

🍑2.理解#define的 两个要点

📝【小总结】

🍑3.核心计算:只替换不计算(两道例题)

下面是一个简单的例子来帮助你理解 #define 的只替换不计算:

🌳例题1详解

#include <stdio.h>  
  
#define SQUARE(x) x * x  
  
int main() {  
    int a = 5;  
    int b = SQUARE(a + 1); // 这里会替换为 (a + 1) * (a + 1),而不是 (a * a) + 1  
    printf("b = %d\n", b); // 输出 36,而不是预期的 26  
  
    // 为了得到正确的平方和加1,你需要使用括号来确保运算顺序  
    #define CORRECT_SQUARE(x) ((x) * (x))  
    int c = CORRECT_SQUARE(a + 1); // 这里会替换为 ((a + 1) * (a + 1))  
    printf("c = %d\n", c); // 输出 36,这是正确的 (a + 1) 的平方  
  
    // 另一个例子,显示没有计算  
    #define MULTIPLY_BY_TWO(x) x * 2  
    int d = MULTIPLY_BY_TWO(5 + 3); // 这里会替换为 5 + 3 * 2,由于运算符优先级,结果是 11 而不是 16  
    printf("d = %d\n", d); // 输出 11  
  
    return 0;  
}

这个例子中,你可以看到 SQUARE(a + 1) 被替换为 (a + 1) * (a + 1),而不是你可能期望的 (a * a) + 1。同样,MULTIPLY_BY_TWO(5 + 3) 被替换为 5 + 3 * 2,由于乘法优先级高于加法,所以结果是 11 而不是 16。

为了避免这类问题,你需要在宏定义中谨慎使用括号,以确保运算顺序和优先级与你的预期相符。

🌳例题2详解


‍ #define N 3  
 #define Y(n) ((N+1)*n)

则执行语句z=2*(N+Y(5+1));后,z的值为( )。
接下来,我们要执行语句 z=2*(N+Y(5+1));。在这个语句中,Y(5+1) 宏会被替换。

📝【替换过程】

Y(5+1) 替换为 ((N+1)(5+1))(注意这里 n 被替换为 5+1)。
由于 N 被定义为 3,所以 ((N+1)
(5+1)) 替换为 ((3+1)*(5+1))。

现在,完整的表达式 z=2*(N+Y(5+1)); 变为:

z = 2 * (3 + ((3+1)*(5+1)));

计算这个表达式:

z = 2 * (3 + (4*6));  
z = 2 * (3 + 24);  
z = 2 * 27;  
z = 54;

🌳定义带参数的宏进行循环计算

#include <stdio.h>  
  
#define SUM_UP_TO(n) ((n > 0) ? (n + SUM_UP_TO(n-1)) : 0)  
  
int main() {  
    int sum = SUM_UP_TO(5); // 这将展开为 5 + 4 + 3 + 2 + 1 + 0  
    printf("Sum up to 5 is %d\n", sum); // 输出 15  
    return 0;  
}

🍑4.#define使用注意事项

🌳注意1

📝【看看前面的和定义宏函数的注意点和例题就知道啦!】

🌳注意2

符号常量同名的问题:
以下写法是正确的

#include"stdio.h" 
#define PROD 2 * 5
#define PROD 2  *  5
int main()
{
	printf( "%d", PROD );
	return 0;	
}

但是以下使用#define定义PROD 会提示告警:第三行代码“PROD ”redefiened
也就是说,使用#define定义重复的符号常量时,如果运算符的前后都有空格,则不提示告警,否会提示告警。因此使用#define带有运算符的常数之间的运算需要注意符号常量不要重名。

🍑5.#define和函数对比(了解)

宏通常被应用于执行简单的运算,比如在两个数中找出较大的一个

#define MAX(a, b) ((a)>(b)?(a):(b))

那为什么不用函数来完成这个任务?原因有二:

用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹 
更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于来比较的类型。宏是类型无关的

百问C语言第1问——彻底弄懂define用法-LMLPHP
宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到

#define MALLOC(num, type)\
(type *)malloc(num * sizeof(type))
...
//使用
MALLOC(10, int);//类型作为参数
//预处理器替换之后:
(int*)malloc(10 * sizeof(int));

百问C语言第1问——彻底弄懂define用法-LMLPHP

🍑【总结】

1.宏定义是在预处理阶段进行的,所以在定义宏时不需要在末尾添加分号(;)。

2.由于宏定义只是简单的文本替换,所以定义宏函数时要特别注意参数的使用,确保在替换后不会产生语法错误或逻辑错误。

3.#define 定义的宏是全局的,可以在文件的任何地方访问。

4.#undef 指令用于取消之前定义的宏。

5.宏定义通常用于常量定义和简单的函数替换,对于复杂的函数或功能,建议使用函数来实现。

百问C语言第1问——彻底弄懂define用法-LMLPHP

🍑【写在后面】

百问C语言系列之后会陆续更新,看看小编码字的份上,各位帅哥和姐姐麻烦给个关注,如果喜欢,可以点赞和收藏我的专栏,虽然小编目前大一非科班,不过我会继续更新我的内容,努力成长。如果内容出现错误,恳请批评指正。
百问C语言第1问——彻底弄懂define用法-LMLPHP
点击这里,查看所有玩转指针专栏的文章!
点击这里,查看所有百问C语言栏的文章!

05-12 10:41