今天我们所讲的内容分为以下几个方面:
__FILE__ // 进?编译的源?件__LINE__ // ?件当前的?号__DATE__ // ?件被编译的?期__TIME__ // ?件被编译的时间__STDC__ // 如果编译器遵循 ANSI C ,其值为 1 ,否则未定义
#include<stdio.h>
int main()
{
printf("file:%s line:%d\n", __FILE__, __LINE__);
return 0;
}
运行结果:
基本语法:# define name stuff
# define MAX 1000# define reg register // 为 register 这个关键字,创建?个简短的名字# define do_forever for(;;) // ?更形象的符号来替换?种实现# define CASE break;case // 在写 case 语句的时候自动把 break 写上。# define DEBUG_PRINT printf( "file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ , \__DATE__,__TIME__ )// 如果定义的 stuff 过?,可以分成几行写,除了最后??外,每行的后?都加?个反斜杠 ( 续行符 ) 。
#define 机制包括了?个规定,允许把参数替换到?本中,这种实现通常称为宏(macro)或定义宏 (define macro)。
声明方式:# define name( parament-list ) stuff
#define ADD(a,b) a+b
这就声明好一个加法宏了,但是这样定义宏存在?个问题:
观察下面的代码:
#include<stdio.h>
#define SQUARE(x) x * x
int main()
{
int a = 8;
int b = 9;
printf("%d",SQUARE(a + b));
return 0;
}
那么大家觉得打印的多少?
有人可能会说:a+b=8+9=17
17*17=289
但真的是这样吗?
我们来看看结果:
结果是89,为什么呢?
我们吧鼠标移动到函数上,我们会发现:
替换文本时,参数x被替换成a + b,所以这条语句实际上变成了:a+b*a+b
# define SQUARE(x) (x) * (x)
# define DOUBLE(x) (x) + (x)
int a = 5 ;printf ( "%d\n" , 10 * DOUBLE(a));
printf ( "%d\n" , 10 * ( 5 ) + ( 5 ));
# define DOUBLE( x) ( ( x ) + ( x ) )
注: 所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使?宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
x+ 1 ; // 不带副作用x++; // 带有副作用
# define MAX(a, b) ( (a) > (b) ? (a) : (b) )...x = 5 ;y = 8 ;z = MAX(x++, y++);printf ( "x=%d y=%d z=%d\n" , x, y, z);
z = ( (x++) > (y++) ? (x++) : (y++));
x=6 y=10 z=9
在程序中扩展#define定义符号和宏时,需要涉及几个步骤:1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#define MAX(a, b) ((a)>(b)?(a):(b))
宏和函数相比的优势:
1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜?筹。2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于 > 来比较的类型。宏是类型无关的。
1. 每次使用宏的时候,?份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。2. 宏是没法调试的。3. 宏由于类型无关,也就不够严谨。4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
#define MALLOC(num, type)\
(type )malloc(num sizeof(type))
...
//使?
MALLOC(10, int);//类型作为参数
//预处理器替换之后:
(int )malloc(10 sizeof(int));
#define PRINT(n) printf("the value of "#n " is %d", n);
printf("the value of ""x" " is %d", x);
这样就能打出 the value of x?is 1?.
int int_max(int x, int y)
{
return x>y?x:y;
}
float float_max(float x, float y)
{
return x>y?x:y;
}
这里我们就可以使用宏定义来解决:
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \
return (x>y?x:y); \
}
但是,其实在实际开发过程中##使用的很少,很难取出贴切的例子
把宏名全部大写函数名不要全部大写
这条指令用于移除?个宏定义。
# undef NAME// 如果现存的?个名字需要被重新定义,那么它的旧名字?先要被移除。
比如说:调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。
常见的条件编译指令:1.# if 常量表达式????????//...# endif// 常量表达式由预处理器求值。如:# define __DEBUG__ 1# if __DEBUG__????????//..# endif2. 多个分支的条件编译# if 常量表达式????????//...# elif 常量表达式????????//...# else????????//...# endif3. 判断是否被定义# if defined(symbol)# ifdef symbol# if !defined(symbol)# ifndef symbol4. 嵌套指令# if defined(OS_UNIX)????????# ifdef OPTION1????????????????unix_version_option1();????????# endif????????# ifdef OPTION2????????????????unix_version_option2();????????# endif# elif defined(OS_MSDOS)????????# ifdef OPTION2????????????????msdos_version_option2();????????# endif# endif
本地文件包含 :# include "filename"
库文件包含:# include <filename>