我的闹钟提醒我,今天是记录自己学习的一天!
一、宏的作用
首先,我们谈谈宏的作用,明白为什么学它,这样我们才有学习它的乐趣。
🎃这是第一个作用:
⭐️宏能够对常量进行控制
例如:
🐵控制定义数组的长度
#define M 100
int main(){
int shuju[M];
return 0;
}
🎃第二个作用:
⭐️⭐️宏和条件编译指令相配合,能进行条件编译
例如:
🐵1)防止头文件的多重包含(防止头文件多重包含机制)
头文件条件编译应这样写:
#include<stdio.h>
#include<stdlib.h>
#ifndef _H_FILENAME_
解释:该宏没被定义过,则编译条件为真,编译器继续编译下面的代码,否则跳过以下代码
#defile _H_FILENAME_
解释:定义一个以头文件命名的宏(编译宏),这样该头文件在第二次包含的时候编译条件被判断为假。
写头文件内容,比如函数声明等
#endif
解释:编译宏结束符
🐵2)根据不同的编译器,选择不同的代码段,提高代码的可移植性
🎃第三个作用:
⭐️⭐️⭐️对应码(比如:寄存器、功能码、状态码、指令码、指令参数码)
🐵1)减少具体码出错(即有语义的标识符一旦出错,编译器会报错)
🐵2)方便开发人员记忆(即有语义的标识符比无语义的数字好记)
二、宏的定义
我们现在已经弄明白宏的作用了,那就开始学习宏是怎么定义的吧?😁
宏的定义:#define 宏名 宏体
宏名要符合C语言命名规则,且一般要求全部大写,以便程序员区分宏和函数
宏体可以是常量、表达式、字符串等
比如:#define M 100
宏又分为带参数宏与不带参数宏
带参数宏:#define MAX a>b?a:b
不带参数宏:#define PI 3.1415926
三、宏的条件编译(详)
🎃1)#undef NAME
//定义形式
作用:用于取消已定义的宏
🎃2)条件编译
#if 常量 //其中常量可为常量表达式、常量宏、常变量……
··· //写声明语句
#endif //结束
#if 常量
头文件内容
#elif 常量
头文件内容
#endif
⭐️如果没有定义宏,就编译声明语句(头文件内容)
#ifndef FILE_NAME 或者 #if !define(FILE_NAME)//这两种形式都可以
#define FILE_NAME
头文件内容
#endif
⭐️⭐️如果定义了宏,就编译声明语句(头文件内容)
#ifdef FILE_NAME 或者 #if define(FILE_NAME)
#undef FILE_NAME
头文件内容
#endif
四、宏与函数的比较
学完宏,我们知道:宏与函数的功能有一些类似。那么有人就想问了:宏与函数到底有什么具体的区别呢?不急,下面我们就一起来分析分析。
由于纯文字的对比比较枯燥费眼,我就借助图表的形式为为大家展现,缓解一下大家的视觉疲劳:
宏与函数的区别
可能图表有的地方看不太明了,我就列举一些例子为大家解释:
🐵1)用宏的方式求值:
#define M a+b
int main(){
int a=8,b=2,c=1;
int d;
d=a*M+c;
printf("%d",d);
return 0;
}
预料结果是:81
实际输出结果是:67
这是因为宏在预处理时就已经被替换,即:d=aa+b+c;
而我们想要的表达式是:d=a(a+b)+c;
因此,我们要注意对宏的保护,即宏中多加括号是有必要的
🐵2)宏的副作用:
#define MAX(a,b) a>b?a:b
int main(){
int a=9,b=2;
printf("较大值是:%d",MAX(++a,++b) );
return 0;
}
预料结果 较大值是:10
实际输出结果 较大值是:11
这是因为 a ,b 都在传递过程中自增了两次,导致结果错误
而调用函数,其结果是10,正确
好了,大家能看到这,这篇文章算是圆满结尾了。🎃