宏和函数对比
宏#define DOUBLE(x) ((x)+(x))也可以通过函数实现,那么为什么不用函数来实现呢?
这就要说说宏和函数的区别了
宏的优点:
用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多,函数需要创建栈帧等等,所以宏比函数在程序的规模和速度方面更胜一筹。
宏与类型无关在前面我们定义的各个宏中可以看出,宏中的参数不需要指明类型,函数的参数必须声明为特定的类型,所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等
宏的缺点:
每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
宏是没法调试的。
宏由于与类型无关,所以也就不够严谨。
宏可能会带来运算符优先级的问题,导致程容易出现错。
所以最好使用宏去执行一些简单的运算
宏和函数的使用语法很相似,所以我们一般无法通过语言本身区别宏和函数
所以要有一个习惯: 把宏的名全部大写,函数名不全大写
3.#undef
#undef用于移除一个宏定义
#undef NAME/ /如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
观察一下代码:
#define MAX 1000 int a = MAX; #undef MAX int b = MAX
在VS中,我们可以看到第二个MAX报错了,因为#undef已经移除了上面的宏定义
4.条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。
或者我们编写一个可移植的代码,在不同平台就要编译不同部分的代码
下面是几个常见的条件编译指令:
1.
#if 常量表达式 //如果为真,#if与#endif中的语句参加编译,如果为假则不参加编译 //... #endif //... 1
举个例子:
#define __DEBUG__ 1 int main() { #if __DEBUG__ printf("hehe"); #endif printf("haha"); }
__DEBUG__ 值为1,为真,所以会编译
结果会输出:hehehaha
对于会编译和不会编译的语句,在IDE中会呈现不同的颜色
2.
多个分支的条件编译
#if 常量表达式 //... #elif 常量表达式 //... #else //... #endif 1
示例:
#define M 2 int main() { #if M ==0 printf("0"); #elif M ==1 printf("1"); #elif M==2 printf("2"); #else printf("3"); #endif }
该代码只会编译printf("2");语句
3.判断是否被定义
//被定义 #if defined(symbol) #ifdef symbol //未被定义 #if !defined(symbol) #ifndef symbol
示例:
#define A #define B int main() { #ifdef A printf("yes\n"); #endif return 0; #if defined(B) printf("yes\n"); #endif return 0; #if !defined(C) printf("no\n"); #endif return 0; #ifndef C printf("no"); #endif return 0; }
4.上面那些判断条件也可以如if else语句一样嵌套使用
5.文件包含
头文件的包含
本地文件包含:
#include "filename"
1
查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。
库文件包含:
#include <filename.h> 1
如果还按照本地文件的包含从源文件所在目录下开始找是在浪费时间,因为库文件不可能在源文件所在目录下。
所以将文件名用<>扩起来,就是让程序直接从标准位置查找头文件。
对于库函数,也是可以用""包含的,就是查找的效率就低些,也不容易区分是库文件还是本地文件。
嵌套文件包含
如果一个程序中,包含了许多文件,并且这些文件中存在重复文件,在预处理阶段这些都会被导入,这回导致程序冗余
如何解决这个问题,答案就是:条件编译
在每个头文件的开头写:
#ifndef __TEST_H__ #define __TEST_H__ //头文件的内容 #endif 1
2
3
4
举个例子,如图:
当某个源文件第一次导入这个头文件,先走#ifndef __TEST_H__语句,发现 __TEST_H__并未定义,所以接下来运行#define __TEST_H__定义了这个标识符,如果这个源文件又导入了这个文件,当运行到#ifndef __TEST_H__是会发现已经定义了 __TEST_H__,所以就不会包含#ifndef和#endif间的语句了.
或者
#pragma once