1.预处理标识符的使用:
#include<stdio.h>
#define __FILE__ //进行编译的源文件
#define __LINE__ //文件当前的行号
#define __DATE__ //文件被编译的日期
#define __TIME__ //文件被编译的时间
int main()
{
printf("file:%s\n", __FILE__);
printf("line:%d\n", __LINE__);
printf("date:%s\n", __DATE__);
printf("time:%s\n", __TIME__);
return 0;
}
执行结果:
<img src="https://img-blog.youkuaiyun.com/20161018185101086?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
这样可以输出当前编译文件的相关信息,使用非常方便。
2.了解宏和函数的区别
使用宏的语法和使用函数的语法是完全一样的,所以语言本身不能区分这两者,一般情况下,我们将宏的名字全部用大写来区分。
宏可以非常频繁的用于执行简单的计算,比如:
#define MAX(a,b) ((a)>(b)?(a):(b)) //求两个数中较大的一个
为什么不用函数来完成,有两个原因:
1)用于调用和函数返回的代码很可能比实际执行这个小型计算工作的代价大,所以使用宏比使用函数在程序的规模和速度更胜一筹。
2)但是更重要的是,函数的参数必须申明为一种特定的类型,所以函数只能在类型合适的表达式上使用。反之,宏可以用于整形、长整形......以及其他任何可以使用>操作符
比较大小的类型。
宏是和类型无关的。
和函数相比,使用宏的不好处在于每次使用时,都要将宏定义的代码拷贝到程序中,除非宏非常短,否则使用宏可能会大幅度增加程序的长度。
还有一些任务函数无法实现,比如:
#include<stdio.h>
#define MALLOC(n,type) ((type*)malloc((n)*sizeof(type)))
int main()
{
int *pi = MALLOC(25, int);
return 0;
}
这个程序经过预处理后得到:
int main()
{
int *pi = ((int*)malloc((25)*sizeof(int)));
return 0;
}
这个宏的第二个参数是一种类型,它无法作为函数参数进行传递。
3.宏参数的副作用
当宏参数在宏定义中出现次超过一次时,如果这个参数具有副作用,那么使用时就有可能导致不可预料的结果。比如
x++;
#include<stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 2;
int y = 8;
int z = MAX(x++, y++);
printf("x=%d\n", x);
printf("y=%d\n", y);
printf("z=%d\n", z);
return 0;
}
得到结果:
在这个程序中较小值计算了一次,但是较大值却计算了两次。
4.编译链接的整个过程
1)预处理过程
(1)宏替换
(2)头文件展开
(3)取消注释
(4)条件编译
在编译一个程序时,如果我们可以选择某条语句或某组语句进行翻译或者被忽略,就会很方便,条件编译就是用于实现这个目的的。
2)编译过程(c程序代码到汇编)
3)汇编过程(汇编到二进制)
4)链接过程(将二进制生成可执行程序的过程)
比如:
#include<stdio.h>
#define DEBUG 1 //DEBUG被定义则执行语句,值为1时执行,为0时不执行
#define REALSE 1
int main()
{
#if DEBUG
printf("hello.\n");
printf("happy.\n");
#elif REALSE
printf("wwww\n");
#else
printf("aaa\n");
#endif
return 0;
}
执行结果: