本篇接上篇程序环境和预处理(1)所讲
目录
1.#define
1.1#define 定义标识符
#define name stuff
举个例子:
1.2 #define定义宏
宏的申明方式
#define name(parament-list) stuff
注意 参数列表的左括号必须和name紧邻
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
下面再说一个容易错的地方
第一眼你会认为将打印 36, 实际上将打印 11.
要想将36打印出来,在宏定义上加括号就可以解决这个问题
所以,在使用#define宏定义时,不要吝啬括号
还有两个注意事项、
1.宏,不能出现递归
2.当预处理搜索#define定义的符号时,字符串常量内容并不被搜索
1.3 #和##
下面我们可以看这段代码
可以发现字符串有自动连接的特点。
根据这样的特点我们可以
使用#,把一个宏参数变成对应的字符串
#define PRINT(N, format) printf("the value of "#N" is "format"\n", N)
int main()
{
int a = 20;
double pai = 3.14;
PRINT(a, "%d");
PRINT(pai, "%lf");
return 0;
}
使用##,把位于它两边的符号合成一个符号
它允许宏定义从分离的文本片段创建标识符
#define CAT(name, num) name##num
int main()
{
int class105 = 105;
printf("%d\n", CAT(class, 105));
return 0;
}
1.4 带副作用的宏参数
下面我们看一段代码
#define MAX(x, y) ((x)>(y)?(x):(y))
int main()
{
int a = 5;
int b = 8;
int c = MAX(a++, b++);
//int c = ((a++) > (b++) ? (a++) : (b++));
printf("%d\n", c);//
printf("%d\n", a);//
printf("%d\n", b);//
return 0;
}
通过这段代码我们发现
当宏参数在宏的定义中出现超过一次时,如果参数带有副作用,那么你在使用这个宏时可能出现危险,导致不可预测的后果,副作用就是表达式求值的时候出现的永久性效果
1.5 宏和函数对比
宏通常被用于执行简单的运算
属性 | #define定义宏 | 函数 |
---|---|---|
代码长度 | 在大多数时候使用程序长度都很长 | 函数代码只出现一个地方,使用时就调用那一个地方的代码 |
执行速度 | 更快 |
有函数调用和返回,相对慢一些 |
操作符优先级 | 需要多加些括号,以防出现一些不可预料的后果 | 函数参数只在调用时求值一次结果传给函数,表达式求值更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体的多个位置 | 函数参数只在传参数求值一次,结果更容易控制 |
参数类型 | 宏的参数和类型无关 | 参数与类型有关,如果参数类型不同,就需要不同的函数,即使执行任务相同 |
调试 | 宏不方便调试 | 可以逐语句调试 |
递归 | 不能递归 | 可以递归 |
1.6命名约定
把宏名全部大写
函数名不要全部大写
2.#undef
#undef NAME //用于移除一个宏定义
//如果现存的一个名字需要被重新定义,那么它的旧名字先要被移除
3.命令行定义
许多C的编译器提供一种能力,允许在命令行中定义符号 。用于启动编译过程
例如:当我们根据同一个源文件要编译出不同的一个程序的不同版本的时候 ,这个特性有点用处(假定某个程序中声明了一个某个长度的数组,如果机器内存有限 ,我们需要 一个很小的数组,但是另外一个机器内存大写,我们需要一个数组能够大写 。)
4.条件编译
在编译一个程序的时候我们如果要将一条语句编译或放弃是很方便的,我们用条件编译指令就可以满足。
下面我们看这段代码
#define MAX 0
int main()
{
#if defined(MAX)
printf("hehe\n");
#endif
#if !defined(MAX)
printf("hehe\n");
#endif
#ifdef MAX
printf("hehe\n");
#endif
#ifndef MAX
printf("hehe\n");
#endif
return 0;
}
常见的编译指令
1. #if 常量表达式
//…
#endif
2.多条件的条件编译
#if 常量表达式 //…
#elif 常量表达式 //…
#else 常量表达式 //…
#endif 常量表达式 //…
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#endif
5.文件包含
5.1 头文件被包含的方式
#include”filename”
先在源文件所在目录下找,如果未找到,编译器就像查找库函数头文件一样在 标准位置查找头文件
#include<filename>
直接去标准路径下去查找
注意:这里对于库文件也可以用“”来包含
但这样效率就低一些,也不容易区分是库文件还是本地文件了。
5.2 嵌套文件包含
这样的嵌套文件包含可以用条件编译来解决
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/87395.html