宏定义
被定义为
“
宏
”
的标识符称为
“
宏名
”
。在编译预处理时
,
对程序中所有出现的
“
宏名
”,
都用宏定义中的字
符串去代换
,
这称为
“
宏代换
”
或
“
宏展开
”
。
宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。在
C
语言中
,“
宏
”
分
为有参数和无参数两种。
##
不带参数的宏定义
格式
:
#define
标识符 字符串
其中的
“#”
表示这是一条预处理命令。凡是以
“#”
开头的均为预处理命令。
“define”
为宏定义命令。
“
标识符
”
为所定义的宏名。
“
字符串
”
可以是常数、表达式、格式串等。
注意点
:
1)
宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误
2)
对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作
3)
在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候
才对已经展开宏名的源程序进行语法检查
#include <stdio.h>
//
源程序中所有的宏名
PI
在编译预处理的时候都会被
3.14
所代替
#define PI 3.14
//
根据圆的半径计
radius
算周长
float
girth
(
float
radius
) {
return
2
*
PI
*
radius
;
}
int
main
()
{
float
g
=
girth
(
2
);
printf
(
"
周长为:
%f"
,
g
);
return
0
;
}
#define R 10
int
main
()
{
char *
s
=
"Radio"
;
//
在第
1
行定义了一个叫
R
的宏,但是第
4
行中
"Radio"
里面的
'R'
并不会被
替换成
10
return
0
;
}
代码情缘
4)
宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用
#undef
命令
5)
定义一个宏时可以引用已经定义的宏名
6)
可用宏定义表示数据类型
,
使书写方便
带参数的宏定义
C
语言允许宏带有参数。在宏定义中的参数称为形式参数
,
在宏调用中的参数称为实际参数。对带参
数的宏
,
在调用中
,
不仅要宏展开
,
而且要用实参去代换形参
格式
:
#define
宏名
(
形参表
)
字符串
#define I 100
int
main
()
{
int
i
[
3
]
=
I
;
return
0
;
}
#define PI 3.14
int
main
()
{
printf
(
"%f"
,
PI
);
return
0
;
}
#undef PI
void
test
()
{
printf
(
"%f"
,
PI
);
//
不能使用
}
#define R 3.0
#define PI 3.14
#define L 2*PI*R
#define S PI*R*R
#define String char *
int
main
(
int
argc
,
const
char *
argv
[])
{
String str
=
"This is a string!"
;
return
0
;
}
代码情缘
//
第
1
行中定义了一个带有
2
个参数的宏
average
,
#define average(a, b) (a+b)/2
int
main
()
{
//
第
4
行其实会被替换成:
int a = (10 + 4)/2;
,
int
a
=
average
(
10
,
4
);
//
输出结果为:
7
是不是感觉这个宏有点像函数呢?
printf
(
"
平均值:
%d"
,
a
);
return
0
;
}
注意点
:
1)
宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串
.
#define average (a, b) (a+b)/2
int
main
()
{
int
a
=
average
(
10
,
4
);
return
0
;
}
注意第
1
行的宏定义,宏名
average
跟
(
a
,
b
)
之间是有空格的,于是,第
5
行就变成了这样:
int
a
=
(
a
,
b
) (
a
+
b
)
/
2
(
10
,
4
);
这个肯定是编译不通过的
2)
带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,
一般用一个小括号括住字符串的参数。
#include <stdio.h>
//
下面定义一个宏
D(a)
,作用是返回
a
的
2
倍数值:
#define D(a) 2*a
//
如果定义宏的时候不用小括号括住参数
int
main
()
{
//
将被替换成
int b = 2*3+4;
,输出结果
10
,如果定义宏的时候用小括号括住参数,把上面的第
3
行改
成:
#define D(a) 2*(a)
,注意右边的
a
是有括号的,第
7
行将被替换成
int b = 2*(3+4);
,输出结果
14
int
b
=
D
(
3
+
4
);
printf
(
"%d"
,
b
);
return
0
;
}
3)
计算结果最好也用括号括起来
代码情缘
条件编译
在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编
译
(
只有参与编译的代码最终才能被执行
)
,这就是条件编译。
为什么要使用条件编译
1)
按不同的条件去编译不同的程序部分
,
因而产生不同的目标代码文件。有利于程序的移植和
调试。
2)
条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序进行编译
,
生成
的目标代码程序很长
,
而采用条件编译
,
则根据条件只编译其中的程序段
1
或程序段
2,
生成的目
标程序较短。
##if-#else
条件编译指令
第一种格式
:
它的功能是
,
如常量表达式的值为真
(
非
0),
则将
code1
编译到程序中
,
否则对
code2
编译到程序
中。
注意
:
是将代码编译进可执行程序
,
而不是执行代码
条件编译后面的条件表达式中不能识别变量
,
它里面只能识别常量和宏定义
#include <stdio.h>
//
下面定义一个宏
P(a)
,作用是返回
a
的平方
#define Pow(a) (a) * (a)
//
如果不用小括号括住计算结果
int
main
(
int
argc
,
const
char *
argv
[]) {
//
代码被替换为
:int b = (10) * (10) / (2) * (2);
//
简化之后:
int b = 10 * (10 / 2) * 2;
,最后变量
b
为
:100
int
b
=
Pow
(
10
)
/
Pow
(
2
);
printf
(
"%d"
,
b
);
return
0
;
}
#include <stdio.h>
//
计算结果用括号括起来
#define Pow(a) ( (a) * (a) )
int
main
(
int
argc
,
const
char *
argv
[]) {
//
代码被替换为
:int b = ( (10) * (10) ) / ( (2) * (2) );
//
简化之后:
int b = (10 * 10) / (2 *2);
,最后输出结果:
25
int
b
=
Pow
(
10
)
/
Pow
(
2
);
printf
(
"%d"
,
b
);
return
0
;
}
#if
常量表达式
..
code1
...
#else
..
code2
...
#endif
代码情缘
第二种格式
:
typedef
关键字
C
语言不仅