预处理
如:#include<stdio.h>,宏定义命令#define PI 3.14 等。
在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分。
1、无参宏定义
无参宏的宏名后不带参数。
其定义的一般形式为:#define 标识符 字符串
其中“#”表示这是一条预处理命令。
define为宏定义命令。“标识符“为所定义的宏名。”字符串“可以是常数,表达式,格式串等。
例:#define PI 3.14
它的作用是指定标识符PI来代替数3.14。
在编写源程序时,所有的3.14都可以用PI来代替,而对源程序做编译时,将先有预处理程序做宏代换,即用3.14表达式去置换所有的宏名PI,然后再进行编译。
例:
#include<stdio.h> #include "StdAfx.h" #define PI 3.14 void main() { double s; int r; scanf("%d",&r); s=r*r*PI; printf("%g\n",s); }
说明:(1)宏命令是在一种简单的代换,字符串中可以是任何字符,常量或表达。预处理程序不会做任何检查,若有错误,只能在编译已被宏展开的源程序时发现。
(2)宏命令不是说明或语句,不必加分号,若加分号,则连分号也一并置换。
(3)宏命令必须写在函数之外,其作用域为宏定义命令起到源程序结束,如要终止其作用域可使用#undef命令。
(4)宏名在源程序中若用引号括起,则预处理程序不对其作宏代换。
例:
#include<stdio.h> #include "StdAfx.h" #define PI 3.14 void main() { void fun(void); double s; int r; scanf("%d",&r); s=r*r*PI; printf("%g\n",s); fun(); } void fun(void) { printf("PI=%g\n",PI); printf("PI\n\n"); }
(5)宏定义允许嵌套,在宏定义的字符串中可以使用已定义的宏名。在宏展开时有预处理程序层层代换。
(6)习惯上宏名用大写字母表示,以便于与变量区别,但也允许小写字母。
(7)可用宏定义表示数据类型,使书写方便。
例:#define INTEGER int
注:宏定义表示数据类型和typedef定义数据说明符的区别:宏定义是简单的字符串代换,是在预处理完成的,它不是简单的代换,而是对类型说明符重命名。被命令的标识符具有类型定义说明的功能。
例:
#include<stdio.h> #include "StdAfx.h" #define PIN1 char* typedef char*PIN2; void main() { PIN1 x,y; PIN2 a,b; printf("#define:%d %d\n\n",sizeof(x).sizeof(y)); printf("typedef:%d %d\n\n",sizeof(a),sizeof(b)); }
(8)对“输出格式”做宏定义,可以减少书写的麻烦。
例:
#include<stdio.h> #include "StdAfx.h" #define P printf #define D "%d\n" #define F "%f\n" void main() { int a=5,c=8,e=11; float b=3.8,d=9.1,f=21.08; P(D F,a,b); P(D F,c,d); P(D F,e,f); }
2、带参宏定义
C中允许宏带有参数,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。
对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
定义的一般形式为:#define 宏名(形参表)字符串
调用的一般形式为:宏名(实参表);
例:#define M(y) y*y+3*y /*宏定义*/
……
K=M(5) /*宏调用*/
……
在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5*+3*5;
例:
#include<stdio.h> #include "StdAfx.h" #define MAX(a,b) (a>b)?a:b void main() { int x,y,max; scanf("%d%d",&x,&y); max=MAX(x,y); printf("The max is %d\n",max); }
注:(1)在带参宏定义中,宏名和形参表之间不能有空格出现。
(2)在带参宏定义中,形参不分配内存单元,因此不必做类型定义,而宏调用中的实参有具体的值,要用他们去代换形参,因此必须要做类型说明。刺出与函数不同,函数调用时进行的是“值传递”,而在带宏参数中,只是符号代换,不存在值传递问题。
(3)在宏定义中形参是标识符,在宏调用中实参是表达式。
例:
#include<stdio.h> #include "StdAfx.h" #define SAY(y) (y)^(y) void main() { int i=0; char say[]={73,72,58,65,101,100,45,100,78}; while(say[i]) { say[i]=SAY(say[i])^say[i]; i++; } printf("%s\n",say); }
(4)在宏定义中,字符串内的形参通常用括号括起来以避免出错。
例:
#include<stdio.h> #include "StdAfx.h" #define SQ(y) (y)*(y) void main() { int a,sq; printf("input a number:"); scanf("%d",&a); sq=160/SQ(a+1); printf("sq=%d\n",sq); }
(5)带参宏与带参函数很相似,但本质上是不同的,同一表达式的处理与用宏处理两者的结果有可能是不同的。
(6)宏定义也可用来定义多个语句,在宏调用时又把这些语句代换到程序内。
例:
#include "StdAfx.h" #include<stdio.h> #include<string.h> #define STR(s1,s2,s3,sum) strcat(strcat(strcat(sum,s1),s2),s3); void main() { char str1[]="I",str2[]="love",str3[]="China",str[40]=""; STR(str1,str2,str3,str); printf("\n\tstr1=%s\n\tstr2=%s\n\tstr3=%s\n\tstr=%s\n",str1,str2,str3,str); }