目录
一、预定义符号
__FILE__ __LINE__ __DATE__ __TIME__ __STDC__ | //进行编译的源文件 //文件当前的行号 //文件被编译的日期 //文件被编译的时间 //如果编译器遵循ANSI C,其值为1,否则未定义 |
举例:
int main()
{
int num1 = 10;
int num2 = 11;
printf("文件地址:%s \n行:%d 日期:%s 时间:%s", __FILE__, __LINE__, __DATE__, __TIME__);
return 0;
}
当我们运行这段代码时,我们可以获取:文件的路径、在第几行进行打印的、当前日期、时间。
二、 #define使用
语法:#define name stuff
#define MAX 1000 //将MAX定义为整型常量1000
#define reg register #define do_forever for(;;) #define CASE break;case | //为 register这个关键字,创建一个简短的名字 //用更形象的符号来替换一种实现 //在写case语句的时候自动把 break写上。 |
// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )
注:name代表的是stuff这个整体,所以我们在使用的时候要注意我们的习惯,有没有加“ ; ”。
定义宏 :
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义
宏(define macro)。
下面是宏的申明方式:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
当我们在定义宏的时候要考虑到运算的优先级,所以,加括号是很重要的。
#define F(A) 2+A*A+1
int main()
{
printf("%d", F(1 + 1));
return 0;
}
对于这段代码,如果我们不考虑优先级,那我们得出的结果应该为:7;但实际运算形式是: 2+1+1*1+1+1 结果应该为6。
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中
的操作符或邻近操作符之间不可预料的相互作用。
#和##用法
请参考:宏中#和##在C语言的作用_qzt__l0ve的博客-CSDN博客
宏和函数对比
在两个数中找出较大的一个。对于这个问题,我们可以写一个宏来完成:
#define MAX(a, b) ((a)>(b)?(a):(b))
相对于用函数实现,你一定喜欢用宏吧。
优势如下:
1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。
宏的缺点:
当然和函数相比宏也有劣势的地方:
1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2. 宏是没法调试的
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
宏和函数的比较
属 性 | #define定义宏 | 函数 |
代 码 长 度 | 每次使用时,宏代码都会被插入到程序中。除了非常 小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每 次使用这个函数时,都调用那个 地方的同一份代码 |
执 行 速 度 | 更快 | 存在函数的调用和返回的额外开 销,所以相对慢一些 |
操 作 符 优 先 级 | 宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括 号。 | 函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数。表达式的求值结果更容易预 测。 |
带 有 副 作 用 的 参 数 | 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 | 函数参数只在传参的时候求值一 次,结果更容易控制。 |
参 数 类 型 | 宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。 | 函数的参数是与类型有关的,如 果参数的类型不同,就需要不同 的函数,即使他们执行的任务是 不同的。 |
调 试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递 归 | 宏是不能递归的 | 函数是可以递归的 |
#undef用法
这条指令用于移除一个宏定义。
#undef NAME //被定义的NAME指令被移除,后面就不能再使用该宏,使用需要重新定义
条件编译 #if #endif #ifdef .....
#if这个用法其实与if语句用法相似:
(1)
#if 常量表达式 //常量表达式为真才进行编译
//进行操作。。。。。
#endif //与#if搭配使用,一定要有
(2)
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif //不能少
判断是否被定义
#if defined(symbol)
#if defined(symbol)//判断symbol是否在#define中定义
//。。。。
#endif
举例:
#define NUM 1
int mian()
{
#if defined(NUM)//判断NUM是否有定义,不在乎定义的值
printf("hehe\n");//定义了就打印
#endif
return 0;
}
#ifdef
#ifdef symbol
//...
#endif
//用法与#if defined(symbol)一样,判断symbol是否有定义
反义:
#if !defined(symbol) //#if !defined(syymbol)的反义,即symbol未定义的时候,才执行。
#ifndef symbol //#ifdef的反义。
嵌套指令
使用时要注意分别、每组的搭配不能乱。