C 语言中宏定义分两种,无参的宏和有参的宏
无参数的宏展开目录
无参数宏定义的一般形式为:
- #define name value
- //name是你起的名字,就跟起函数名一样,value是你要给这个名字赋予什么值
- //示例:
- #include <iostream>
- using namespace std;
- #define pi 3.14
- int main()
- {
- int r = 2;
- double s = pi*r*r;
- cout<<s;
- }
这种宏定义要求编译预处理程序将源程序随后所有宏名(注释与字符串常量除外)均用值替换。无参数的宏没什么好说的,但还是有些地方使用时要注意。
几点注意:展开目录
- 在宏定义的#之前可以有若干个空格、制表符,但不允许有其它字符。宏定义在源程序中单独另起一行,换行符是宏定义的结束标志(不能在末尾加分号)。如果一个宏定义太长,一行不 够时,可采用续行的方法。续行是在键人回车符之前先键入符号 "/"。注意回车要紧接在符号 "/" 之后,中间不能插入其它符号。
- 宏定义的有效范围称为宏定义名的辖域(也可以叫做生命周期,类似于变量的生命周期),辖域从宏定义的定义结束处开始到其所在的源程序文件末尾。宏定义名的辖域不受分程序结构的影响。可以用预处理命令 #undef 终止宏定义名的辖域。
- 在新的宏定义中,可以使用前面已定义的宏名,示例:
- # define R 2.5
- # define PI 3.1415926
- # define Circle 2*PI*R
- # define Area PI*R*R
如有必要,宏名可被重复定义。被重复定义后,宏名原先的意义被新意义所代替。
有参数的宏展开目录
有参数宏的定义形式一般为:
- #define name(参数1,参数2,....) sentence//sentencen表示语句
- //示例:
- #define max(a,b) (a)>(b)?(a):(b)
- #include <iostream>
- using namespace std;
- int main()
- {
- int x = max(1+3,1+4);
- cout<<"x = "<<x;//x = 5
- return 0;
- }
注意!注意!注意!我这里为什么 a 和 b 要加括号?我换个示例,如果不加括号,看输出什么
- #define pw(x) x*x
- #include <iostream>
- using namespace std;
- int main()
- {
- int x = pw(3+4);
- cout<<x;
- return 0;
- }
在我给出答案之前,或者我提醒你之前,你估计想不打这会输出什么,你可能会认为会输出 49,但答案是 22。为什么是 22 不是 49?哪里错了?哪里都没错,他只不过依据了正常的加减乘除顺序而已,因为你没加括号,所以他不会将 3+4 作为一个整体来进行乘法运算,而是这个样子 3+4*3+4,先乘除后加减,你说这等于多少?所以在进行宏定义的时候,多加几个括号,总没问题。
带参的宏,类似与函数,看下面的程序,输出我给了,读者可以先分析
- #include <iostream>
- using namespace std;
- #define swap1(a,b) t=a;a=b;b=t;
- int swap2(int c,int d)
- {
- int t;
- t = c;
- c = d;
- d = t;
- }
- int main()
- {
- int a,b,c,d,t;
- a = 5;
- b = 3;
- c = 5;
- d = 3;
- swap1(a,b);
- swap2(c,d);
- cout<<a<<" "<<b<<endl;//3 5
- cout<<c<<" "<<d;//5 3
- return 0;
- }
你会发现函数,并没有交换实参,而宏交换了,但是如果把函数中的参数改为指针或者引用就能成功交换了。下面给出带参的宏和函数的区别:
- 宏会在编译器在对源代码进行编译的时候进行简单替换,不会进行任何逻辑检测,即简单代码复制而已。
- 宏进行定义时不会考虑参数的类型。
- 参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。
- 参数宏的运行速度会比函数快,因为不需要参数压栈 / 出栈操作。
- 函数只在目标文件中存在一处,比较节省程序空间。
- 函数的调用会牵扯到参数的传递,压栈 / 出栈操作,速度相对较慢。
- 函数的参数存在传值和传地址(指针)的问题,参数宏不存在。
宏中”#” 和”##” 的用法展开目录
一般用法:
- 使用 #把宏参数变为一个字符串,用 ## 把两个宏参数贴合在一起
- #include<cstdio>
- #include<climits>
- using namespace std;
- #define STR(s) #s
- #define CONS(a,b) int(a##e##b)
- int main()
- {
- printf(STR(vck)"\n"); //输出字符串"vck"
- printf("%d", CONS(2,3)); // 2e3 输出:2000
- return 0;
- }
- 当宏参数是另一个宏的时候,需要注意凡是宏定义里有用 ''#'' 或 ''##'' 的地方宏参数是不会再展开
- //1.非"#"和"##"的情况
- #include<cstdio>
- #include<climits>
- using namespace std;
- #define TOW (2)
- #define MUL(a,b) (a*b)
- int main()
- {
- printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
- }
- //2. 当有''#''或''##''的时候
- #include<cstdio>
- #include<climits>
- using namespace std;
- #define A (2)
- #define STR(s) #s
- #define CONS(a,b) int(a##e##b)
- int main()
- {
- printf("int max: %s\n", INT_MAX);//INT_MAX
- printf("%s\n", CONS(A, A));//compile error
- }
这个时候,INT_MAX 和 A 都不会在被展开,解决这个问题的方法很简单,多加一层转换宏,加这层宏的用意是把所有宏的参数在中间曾全部展开
- //2.当有"#"或"##"的时候
- #include <bits/stdc++.h>
- using namespace std;
- #define _STR(s) #s
- #define STR(s) _STR(s) // 转换宏
- int main()
- {
- printf("int max: %s\n",STR(INT_MAX));//int max: 2147483647
- return 0;
- }