最近,做OS大作业,编译大作业,和进行实验室工作,强烈认识到了自己对C语言的了解不多……
于是今天老图借了本书,学习一下……
来看一下我最头疼的define……
define的作用:
一是直接定义一个东西……类似标记
譬如:
1 #ifndef test
2 #define test
3 /*
4 balabalabala.
5 */
6 #endif
刘JX老师在大一C++课上教育我们,写头文件一定要加上这么个东西……为什么呢……
再提一下include的事情…… #include<XXXX>,实际上是直接把XXXX整个文件COPY了进来……
如果出现这样的情况:
1 #include <set>
2 #include <map>
我们知道,Cpp的 map 实际上是用 set 做的,map的头文件里肯定有一个 #include <set>,那么,相当于set这个文件在这段程序里面出现了两次……
如果没有ifndef这套的话,相当于将set中的代码重复贴了两次,就粗大事了……
代码第一段ifndef test 代表:如果没有define test,则执行下面的那段,先 define test,然后balabala,最后endif,下次再看到这段代码的时候,ifndef test ,此时会发现test已经define过了,直接endif,中间balabala的代码不会重复两次……
二是直接定义一些……怎么说呢,类似替换规则的东西……
譬如:直接定义常量:
1 #define MAXN 10000
这个实际上就是直接在程序编译之前,将里面的MAXN都替换成10000
预先定义一些常量,好处大家都懂:避免程序内部太多的“magic number”,增强可读性,也便于修改……这里相当于直接替换,貌似C的数组,定义的时候不能用int做下标,const int也不行,只能通过这个方法,用立即数……
譬如:给一些东西改个名字:
1 #include <stdio.h>
2 #define Q scanf
3
4 int main() {
5 int a;
6 Q("%d",&a);
7 printf("%d\n",a);
8 return 0;
9 }
这里有一些玄机:
1:#似乎是因为没有转义?所以不能胡用……
譬如:#define USEMATH #include <math.h> 是不能达到预期效果的……
2:如果这一行太长,可以用\表示和下一行连起来…… 貌似这个'\'也没转义, #define BACKSLASH \ 也是不行的……
譬如:可以定义一些简单的函数:
#define max(a,b) ((a) > (b) ? (a) : (b))
某种意义上这比template NB...
这样,int c = max(a,b); 就自动替换成 int c =((a) > (b) ? (a) : (b)); 了
此处有一个技巧:有的时候,咱们需要用大括号来实现这个"函数",但是,由define直接替换知道,这个替换出来,相当于{/*balabala*/};这样,语法是错的……
于是怎么办呢……咱们可以用 do {/*balabala*/} while(0) 这样的形式,绕开这个问题…… 在上次OS大作业上咱们都见到了……
此处还有两个玄机:一是千万记得要加括号……为什么呢……
譬如:
#define mul(a,b) a * b
看着挺好,mul(1,2 + 3)就出事了…… 直接替换出来,是 1 * 2 + 3,就错了……
正确方法是:#define mul(a,b) ((a) * (b)),万无一失……
另一个玄机是避免++,--之类的,譬如
#define sqr(a) ((a) * (a))
sqr(a++),如果sqr是真的函数的话,计算出没有问题……但是define会忠实的给你替换成((a++) * (a++))……怎么加的不重要,结果就不是你想的了……
最后有两个用法,一个是#,#会将你作为“函数”的“参数”传入的东西转化为字符串;一个是...,作用一看便知:
1 #include <stdio.h>
2 #define max(a,b) ((a) > (b) ? (a) : (b))
3 #define PRINT(
) printf(__VA_ARGS__)
4 #define debug(x) do { \
5 PRINT(#x); \
6 PRINT(" = %d\n",(x)); \
7 }
while (0)
8 9 int main() {
10 int a,b;
11 scanf("%d%d",&a,&b);
12 debug(a);
13 debug(b);
14 debug(a + b);
15 debug(max(a,b));
16 return 0;
17 }