__FILE__:文件名
__TIME__:编译一瞬间的时间
__LINE__:符号所在的行号
__DATE__:文件被编译的日期
#include<stdio.h>
int main()
{
printf("%s\n", __FILE__);
printf("%d\n", __LINE__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
return 0;
}__STDC__判断编译器是否遵循ANSIC,如果遵循,其值为1
在预处理命令阶段完成
#define可以定义常量,也可以定义字符串
#define MAX 10
#define STR "haha"后面也可以加语句(代码)
#define forever for(;;)
int main()
{
forever;
return 0;
}补充:续行符

续行符后面什么都不能有(比如空格) 注意: 不能define后面不能加分号(因为符号替换后也会加分号)

宏与函数类似(没有参数部分,并且直接完成替换)
#define Fuc(x) x*x
int main()
{
int ret = Fuc(3);
printf("%d", ret);
return 0;
}宏定义是直接替换进去的,不会帮你计算,需考虑宏文本里面的优先级和传参的优先级,(当参数传a+1时),解决方法:加括号

有时候整体也要加括号
#define DOUBLE(x) ((x)+(x))

总结:所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻 近操作符之间不可预料的相互作用。
比如:b=a++实现了b=a+1的效果,但产生了a=a+1的副作用
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果
#define MAX(x,y) ((x>y)?(x):(y))
int main()
{
int a = 3;
int b = 5;
int ret = MAX(a++, b++);
printf("%d\n", ret);
printf("%d\n", a);
printf("%d\n", b);
return 0;
}

#define MAX(x,y) ((x>y)?(x):(y))
原因:因为调用函数需要调用函数、执行运算、返回参数需要时间更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形长整型、浮点型等可以用于>来比较的类型。宏的参数是类型无关的

有一些宏可以做到,但函数不能做到的事(可以传类型)
#define Malloc(x,type) (type*)malloc(x*sizeof(type))
int main()
{
int* ptr = Malloc(3, int);
return 0;
}补充:两者效果一样
printf("haha""hehe\n");
printf("hahahehe\n");让参数直接转为字符串变量#a
#define Print(n,format) printf(#n " value is "format"\n",n)
int main()
{
int a = 3;
double b = 4.0;
float c = 7.3f;
Print(a, "%d");
Print(b, "%lf");
Print(c, "%f");
return 0;
}功能:把两端的符号看成一个符号
#define GEN(type) \
type type##_max(type x,type y)\
{\
return x>y?x:y;\
}
GEN(int);
GEN(double);
int main()
{
int ret =int_max(3, 4);
double ret1 =double_max(9.0, 3.0);
printf("%d\n", ret);
printf("%lf\n", ret1);
}#define MAX 10
int main()
{
int a = MAX;
#undef MAX
int b = MAX;
return 0;
}
条件为真,代码段就编译,条件为假,代码段就不编译 常见的条件编译指令:
#if 常量表达式//(表达式可以为零,该表达式的真假判断代码段执行不执行)
……
#endif#define M 7
int main()
{
#if M==0
printf("haha");
#elif M==1
printf("hehe");
#elif M==3
printf("666");
#else
printf("999");
#endif
}第一种写法
#define M
int main()
{
#if defined(M)
printf("haha");
#endif
return 0;
}第二种写法
#define M 2
int main()
{
#ifdef M
printf("haha");
#endif
return 0;
}第三种写法:没定义执行(反过来)
//#define M 2
int main()
{
#if !defined(M)
printf("haha");
#endif
return 0;
}第四种写法
//#define M 2
int main()
{
#ifndef M
printf("haha");
#endif
return 0;
}两种方式的区别
用“add.h”先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误。
#include"add.h"
#include<stdio.h>防止多次包含头文件 有以下方法 方法一:
#ifdef ADD_H
#define ADD_H
int add(int x, int y);
#endif方法二:
#pragma once