宏定义
宏: 在C语言源程序中允许用一个标识符(宏名)来表示一个字符串(常数、表达式、格式串)
define
宏定义命令
宏定义是由源程序中宏定义命令完成的
宏代换(宏扩展): 在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换
#
预处理命令
宏代换是由预处理程序自动完成的
无参宏定义
#define 标识符 字符串
计算: 3 ∗ ( y 2 + 3 y ) + 4 ( y 2 + 3 y ) + 5 ( y 2 + 3 y ) 3*(y^2 + 3y)+4(y^2 + 3y)+5(y^2 + 3y) 3∗(y2+3y)+4(y2+3y)+5(y2+3y)
#include<stdio.h>
#define M (y*y + 3*y)
int main(){
int s,y;
printf("input a number: \n");
scanf("%d",&y);
s = 3*M + 4*M + 5*M;
printf("s=%d \n", s);
}
- 宏名在源程序中若引号
""
括起来,则预处理程序不对其作宏代换
#include<stdio.h>
#define OK 100
int main(){
printf("OK \n");
}
- 宏定义允许嵌套
#include<stdio.h>
#define PI 3.1415926
#define S PI*y*y
int main(){
int y;
printf("please input a number: \n");
scanf("%d",&y);
printf("\n");
printf("PI=%f \n",PI);
printf("S=%f \n",S);
}
-
习惯上宏名用大写字母表示,以便与变量区别. 但允许使用小写字母
-
宏定义表示数据类型,使书写方便
-
对"输出格式"作宏定义,可以减少书写麻烦
#include<stdio.h>
#define P printf
#define D "%d\n"
#define F "%f\n"
int main(){
int a=5, c=8, e=11;
float b=3.8, d=9.7, f=21.08;
P(D F, a,b);
P(D F, c,d);
P(D F, e,f);
}
undef
终止其作用域
宏定义必须写在函数之外,其作用域为宏定义命令起止源程序结束,如要终止其作用域可使用 undef
命令
#include<stdio.h>
#define PI
#define NEW (PI*3)
#undef PI
#define PI 100
int main(){
printf("NEW: %d \n",NEW);
printf("PI: %d \n",PI);
}
带参宏定义
#define 宏名(形参表) 字符串
在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数.
#include<stdio.h>
#define MAX(a,b) (a>b)?a:b
int main(){
int x,y,max;
printf("input two numbers: \n");
scanf("%d%d",&x,&y);
max=MAX(x,y);
printf("max=%d \n",max);
}
- 带参宏定义中,宏名和形参表之间不能有空格出现
- 在宏定义中,形参参数不分配内存单元,因此不必作类型定义.而宏调用中的实参有具体的值.要用它们去代替形参,因此必须作类型说明.
与函数中形参实参区别:
在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行"值传递"
在带参宏中,只是符号代换,不存在值传递问题
3.在宏定义中的形参是标识符,而宏调用中的实参可以是表达式
#include<stdio.h>
#define SQ(y) (y)*(y)
int main(){
int a,sq;
printf("input a number: \n");
scanf("%d",&a);
sq=SQ(a+1);
printf("sq=%d\n",sq);
}
- 在宏定义中,字符串内的形参通常要用括号扩起来以避免出错
即#define SQ(y) (y)*(y)
正确 ( y ) ∗ ( y ) = ( a + 1 ) ∗ ( a + 1 ) = 4 ∗ 4 = 16 (y)*(y)=(a+1)*(a+1)=4*4=16 (y)∗(y)=(a+1)∗(a+1)=4∗4=16 否则#define SQ(y) y*y
与目标相悖 y ∗ y = a + 1 ∗ a + 1 = 3 + 1 ∗ 3 + 1 = 7 y*y=a+1*a+1=3+1*3+1=7 y∗y=a+1∗a+1=3+1∗3+1=7 - 带参的宏和带参的函数很相似,但有本质不同.
把同一表达式用函数处理与用宏处理两者的结果有可能是不同的
#include<stdio.h>
int S(int y){
return ((y)*(y));
}
int main(){
int i=1,answer;
while(i<=5){
answer = S(i++);
printf("%d\n",answer);
}
}
#include<stdio.h>
#define SQ(y) ((y)*(y))
int main(){
int i=1;
while(i<=5){
printf("%d\n",SQ(i++));
}
}
SQ(i++)
被替换成 ((i++)*(i++))
第一循环 i=1 时, 第一个i++为1, 第二个i++ 为2
第二次循环, 即 i=3, 第一个i++为3, 第二个i++ 为4
- 宏定义也可以定义多个语句,在宏调用时,把这些语句又代换到源程序内
#include<stdio.h>
#define SSSV(s1,s2,s3,v) s1=l*w; s2=l*h; s3=w*h; v=w*l*h;
int main(){
int l=3, w=4, h=5, sa,sb,sc,vv;
SSSV(sa,sb,sc,vv);
printf("sa=%d\nsb=%d\nsc=%d\nvv=%d\n",sa,sb,sc,vv);
}
文件包含
#include"文件名"
功能: 把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连接成一个源文件.
eg:
#include<stdio.h>
#include<math.h>
条件编译
可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件
形式1
#ifdef 标识符
程序段1
#else
程序段2
#endif
标识符已被 #define
命令定义过则对程序段1进行编译;否则对程序段2进行编译.
如果没有程序段2(它为空),本格式中#else
可以没有.
#include<stdio.h>
#include<stdlib.h>
#define NUM ok
int main(){
struct stu{
int num;
char *name;
char sex;
float score;
} *ps;
ps = (struct stu*)malloc(sizeof(struct stu));
ps -> num=102;
ps -> name="Miko woo";
ps -> sex='M';
ps -> score=62.5;
#ifdef NUM
printf("Number=%d\nScore=%f\n", ps->num, ps-> score);
#else
printf("Name=%sSex=%c\n", ps->name, ps->sex);
#endif
free(ps);
}
形式2
#ifndef 标识符
程序段 1
#else
程序段 2
#endif
如果标识符未被#define
命令定义过则对程序段1进行编译; 否则对程序段2进行编译.
形式3
# if 常量表达式
程序段 1
#else
程序段 2
#endif
如常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译.
#include<stdio.h>
#define R 1
int main(){
float c,r,s;
printf("input a number:\n");
scanf("%f",&c);
#if R
r = 3.14159*c*c;
printf("area of round is :%f \n", r);
#else
s = c*c;
printf("area of squre is :%f \n", s);
#endif
}