1.#define定义常量
(1)基本语法
#define name stuff
例如
#define MAX 100//定义MAX为100 int main() { //int i = 100; int i = MAX;//与上面是一样的 return 0; } #define reg register //为register这个关键字创建一个简短的名字 #define d0_forever for( ; ;)//用更形象的符号来实现替换 #define CASE break;case //在写case语句时自动把break写上
注: 在define定义标识符的时候建议不要加上;,这样容易导致问题,例如:
#define MAX 1000; if(condition) max = MAX; else max = 0;
如果是加了分号的情况,等替换后,if和else之间就是2条语句,⽽没有⼤括号的时候,if后边只能有⼀ 条语句。这⾥会出现语法错误。
2.#define定义宏
(1)定义
#define 机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏 (define macro)。
(2)审明方式
#define name( parament-list ) stuff
注:参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的⼀部分。
(3)例如
#define SQUARE( x ) x * x
这里宏定义SQUARE(x) = x*x ,宏接收⼀个参数 x
💥💥注意这里会出现一些问题例如下面这个代码段:
int a = 5 ;
printf ( "%d\n" ,SQUARE( a + 1 ) );
乍⼀看,你可能觉得这段代码将打印36,事实上它将打印11,为什么呢?
其实在 替换⽂本时,参数x被替换成a + 1,所以这条语句实际上变成了:
printf ("%d\n",a + 1 * a + 1 );
所以实际上结果为:11
✨✨解决办法:
在宏定义上加上两个括号,这个问题便轻松的解决了~🥳🥳
#define SQUARE(x) (x) * (x)
所以⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的操作符或邻近操作符之间不可预料的相互作⽤。
3.宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。
1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸ 先被替换。
2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复 上述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
4.宏函数的对比
宏通常被应⽤于执⾏简单的运算。
⽐如在两个数中找出较⼤的⼀个时,写成下⾯的宏,更有优势⼀些。
#define MAX(a, b) ((a)>(b)?(a):(b))
那为什么不⽤函数来完成这个任务?
原因有⼆:
1. ⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐函数在程序的规模和速度⽅⾯更胜⼀筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之这个宏怎可以适⽤于整形、⻓整型、浮点型等可以⽤于 > 来⽐较的类型。宏是类型⽆关的。
和函数相⽐宏的劣势:
1. 每次使⽤宏的时候,⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短,否则可能⼤幅度增加程序的⻓度。
2. 宏是没法调试的。
3. 宏由于类型⽆关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
5.#和##
(1)#运算符
#运算符将宏的⼀个参数转换为字符串字⾯量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。
当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 .
就可以写:
#define PRINT(n) printf("the value of "#n " is %d", n);
PRINT(a);//当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",如下所示:
printf("the value of ""a" " is %d", a);
(2)##运算符
## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称 为记号粘合
举个例子:
这⾥我们想想,写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数。
⽐如:
int int_max(int x, int y) { return x>y?x:y; } float float_max(float x, float y) { return x>yx:y; }
但是这样写起来太繁琐了,现在我们这样写代码试试:
//宏定义 #define GENERIC_MAX(type) \ type type##_max(type x, type y)\ { \ return (x>y?x:y); \ }
GENERIC_MAX( int ) // 替换到宏体内后 int##_max ⽣成了新的符号 int_max 做函数名
GENERIC_MAX( float ) // 替换到宏体内后 float##_max ⽣成了新的符号 float_max 做函数名
在实际开发过程中##使⽤的很少.
6.命名约定
⼀般来讲函数的宏的使⽤语法很相似。所以语⾔本⾝没法帮我们区分⼆者。
那我们平时的⼀个习惯是:
把宏名全部⼤写
函数名不要全部⼤写
7.#undef
这条指令⽤于移除⼀个宏定义。
#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。
8.结语
以上就是C语言#define的学习啦~完结撒花🎉🎉🌹🌹🌹,大家有疑问的欢迎在评论区讨论或者私信我哦~