预处理指令
- 1. #define 预处理指令( 用来定义宏)
- 1.1 宏可以用来给数字起名字
- 除了在程序里定义宏代表的数字,也可以在编译命令里面使用-D选项,就可以指定宏所代表的数字
-
#define PI 3.14f //用宏给3.14f这个数字起名字叫π
-
gcc test2.cc -DPI=3.14f
-
- 如果编写程序时需要用到某个数字但是又不知道它的具体数值,就可以在程序里先用宏代表它,然后在编译的时候在临时指定。
- 除了在程序里定义宏代表的数字,也可以在编译命令里面使用-D选项,就可以指定宏所代表的数字
- 1.1 宏可以用来给数字起名字
//希望程序可以得到一张彩票里的随机数,每个随机数在1到36之间。然后再把这些随机数显示在屏幕上。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE = 0
int main() {
//写程序时并不知道彩票里包含多少随机数,无法定义数组里到底有多少个存储区
//用SIZE宏名称带代表数组里存储区个数
int arr[SIZE] = {0};
int num = 0;
srand(time(0));
for (num = 0; num <= SIZE -1; num++) {
//得到一个 1到36 之间的随机数
arr[num] = rand() % 36 + 1;
}
for (num = 0; num <= SIZE - 1 ; num ++) {
printf("%d\n", arr[num]);
}
return 0;
}
/*
g++ -DSIZE=100 test.cc
由SIZE决定输出随机数的数量。
*/
-
- 1.2 宏也可以给计算公式起名字
- 宏的参数表示公式里的未知数
- 1.2 宏也可以给计算公式起名字
#include <stdio.h>
#define PI 3.14f
//定义一个宏叫CIRCLE, 宏的参数都是没有类型名称的
//因为宏的参数都是用替换的方式进行处理的,所以r不一定得代表数字,
#define CIRCLE(r) 2 * PI * r
int main() {
int radius = 0;
printf("请输入半径: ");
scanf("%d", &radius);
printf("周长是%g\n", CIRCLE(radius));
return 0;
}
/*
//gcc 使用-E编译,编译器只会去完成所有预处理指令的处理,会把所有的宏都替换掉,然后显示出来
g++ -E test.cc
output:
...
...
int main() {
int radius = 0;
printf("请输入半径: ");
scanf("%d", &radius);
printf("周长是%g\n", 2 * 3.14f * radius);
return 0;
}
*/
-
- 1.3 编写宏和编写函数不一样的地方
-
-
- 如果希望宏向函数里传递一个数字就必须把宏编写成表达式,用表达式的结果表示要传递的数字
-
-
-
- 宏可以通过参数直接修改函数的存储区内容,因为宏的参数直接代表了函数的存储区,可以直接在宏里修改参数
-
//计算绝对值和相反数
#include <stdio.h>
//下面说的函数就是主函数
//宏不可以使用自己的存储区和函数之间进行数值传递, 宏的参数直接代表了函数的存储区
//所有能当数字的宏,必须要把它写成一个表达式,表达式本身是可以当数字使用的,将表达式结果传递给函数
#define ABS(n) n >=0 ? n : 0 -n
//宏的参数直接代表了函数的存储区,不需要像普通函数那样用指针修改调用函数的存储区,宏直接在宏里修改参数就可以改变主函数的存储区
#define NEG(n) n = 0 -n
//函数里会有一个专门的存储区用来放返回值的,调用函数就会得到那个返回值,但是宏不行,宏没有这样的存储区
int abs(int val) {
if (val >= 0) {
return val;
}
else {
return 0 - val;
}
}
void neg(int *p_val) {
*p_val = 0 - *p_val;
}
int main() {
int val = 0;
printf("请输入一个数字: ");
scanf("%d", &val);
printf("绝对值是:%d\n", abs(val));
printf("绝对值是:%d\n", ABS(val));
neg(&val);
printf("相反数是:%d\n", val);
printf("相反数的相反数是:%d\n", NEG(val));
}
/*
请输入一个数字: -1
绝对值是:1
绝对值是:1
相反数是:1
相反数的相反数是:-1
*/
-
- 1.4 宏注意事项总结
- 如果希望宏向函数传递一个数字就必须把宏编写成一个表达式,用表达式的结果表示要传递的数字
- 宏可以通过参数直接修改函数的存储区内容
- 宏不能保证优先计算宏内部的操作符,所以编写宏的时候,应该把宏写在一对小括号里
- 宏不能保证优先计算宏参数里的操作符,所以编写宏的时候应该把参数写在一对小括号里
- 使用宏的时候不要用自增或者自减的结果做参数
- 1.4 宏注意事项总结
#include <stdio.h>
#define SUB(x, y) ((x) - (y))
int main() {
printf("SUB(10,5)是%d\n", SUB(10, 5));
printf("20 - SUB(10, 5)是%d\n", 20 - SUB(10, 5));
printf("SUB(20, 10 - 5)是%d\n", SUB(20, 10 - 5));
}
/*
output:
SUB(10,5)是5
20 - SUB(10, 5)是15
SUB(20, 10 - 5)是15
*/
-
- 1.5 宏操作符
- # 操作符可以把宏参数转换成字符串字面值
- ## 操作符可以把代表标识符(变量名称, 函数名称等)的宏参数和其他内容连接得到一个新的宏标识符
- 1.5 宏操作符
#include <stdio.h>
#define STR(n) #n
#define PTR(n) p_##n
int main() {
int val = 0;
int *PTR(val) = &val;
STR(2 + 3);
return 0;
}
/*
gcc -E test.cc
output:
...
...
int main() {
int val = 0;
int *p_val = &val;
"2 + 3";
return 0;
}
*/
- 2. 条件编译
- 编译时从一组语句里选择一组编译而忽略其他组
- #ifdef/#ifndef…#esle…#endif 结构可以根据一个宏名称是否被定义过,从两句语句里选择一组进行编译
- 编译时从一组语句里选择一组编译而忽略其他组
#include <stdio.h>
int main() {
#ifdef YI
printf("1\n");
#else
printf("2\n");
#endif
return 0;
}
/*
gcc test.cc
output: 1
gcc test.cc -EYI
output:2
*/
-
- #if…#elif(任意多次)…#else…#endif 结构可以根据任意逻辑表达式从多组语句里选择一组进行编译
代码实例略
- #if…#elif(任意多次)…#else…#endif 结构可以根据任意逻辑表达式从多组语句里选择一组进行编译