深圳网站建设与推广,最好看免费观看高清大全英雄联盟,怎样建个人网站,网站建设需要提供那些资料目录
预处理详解
1.预定义符号
2. #define
2.1 #define定义标识符
2.2 #define 定义宏
2.3 #define 替换规则
注意事项#xff1a;
2.4 #和##
2.5 带副作用的宏参数
2.6 宏和函数对比
3. #undef
4. 条件编译
4.1 单分支条件编译
4.2 多分支条件编译
4.3 判断是…目录
预处理详解
1.预定义符号
2. #define
2.1 #define定义标识符
2.2 #define 定义宏
2.3 #define 替换规则
注意事项
2.4 #和##
2.5 带副作用的宏参数
2.6 宏和函数对比
3. #undef
4. 条件编译
4.1 单分支条件编译
4.2 多分支条件编译
4.3 判断是否被定义
5. 文件包含
5.1 本地文件包含
5.2 库函数包含
5.3 嵌套文件包含
写在最后 预处理详解
思维导图 1.预定义符号
例
#include stdio.hint main()
{printf(%s\n, __FILE__);//进行编译的文件位置printf(%d\n, __LINE__);//文件当前的行号printf(%s\n, __DATE__);//文件被编译的日期printf(%s\n, __TIME__);//文件被编译的时间return 0;
}
输出
输出:
F:\my code\c_plus_plus-code-exercise-warehouse\2023_2_8\2023_2_8\test.c
24
Feb 8 2023
19:49:32
注输出的第一行是我这个文件的路径。
2. #define
2.1 #define定义标识符
#include stdio.h#define print printf
#define size sizeof
#define MAX 1000int main()
{print(hello world\n);print(%d\n, size(int));print(%d\n, MAX);return 0;
}
这个其实就是
1. 用print 代替了 printf
2. 用size 代替了 sizeof
3. 用MAX 代替了 1000。
输出
输出
hello world
4
1000另外建议不要在#define 后面加分号容易出事。
2.2 #define 定义宏
例
#include stdio.h#define mul(x) ((x)*(x))int main()
{int x 3;int ret mul(x);printf(%d\n, ret);return 0;
}
输出
输出9
这个的本质其实就是将mul(x) 替换成 x*x
当然x可以是你指定的值。
例
#include stdio.h#define mul(x) ((x)*(x))int main()
{int x 3;int ret mul(x);printf(%d\n, ret);ret mul(3);printf(%d\n, ret);return 0;
}
输出
输出
9
9
所以这个也是一样的。
注
1. 参数列表的左括号必须与mul你定义的名称紧邻。
2. 用于对数值表达式进行求值的宏定义建议加上确保优先级。
2.3 #define 替换规则
1. 在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号 如果是它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。 对于宏参数名被他们的值所替换。
3. 最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号 如果是就重复上述处理过程。
注意事项
1. 宏参数和#define 定义中可以出现其他#define 定义的符号但是对于宏不能出现递归。
2. 当预处理器搜索#define定义的符号的时候字符串常量的内容并不被搜索。
2.4 #和##
例
#define PRINT(format, x) printf(the value of #x is format\n, x)int main()
{int a 10;//printf(the value of a is %d\n, a);PRINT(%d, a);//printf(the value of a is %d\n, x)int b 20;//printf(the value of b is %d\n, b);PRINT(%d, b);float f 3.14f;PRINT(%f, f);//printf(the value of f is %f\n, x)return 0;
}
输出
输出
the value of a is 10
the value of b is 20
the value of f is 3.140000
总结这里就是使用 # 把一个宏参数变成对应的字符串。
例2
#include stdio.h#define CAT(x,y) x##yint main()
{int helloworld 2023;printf(%d\n, CAT(hello, world));return 0;
}
输出
输出2023
总结##可以把位于它两边的符号合成一个符号。
2.5 带副作用的宏参数
例
#include stdio.h#define MAX(x, y) ((x)(y)?(x):(y))int main()
{int a 3;int b 5;int m MAX(a, b);//宏替换之后//((a)(b)?(a):(b))printf(%d\n, m);printf(%d %d\n, a, b);return 0;
}
输出
输出
6
4 7
因为宏是直接将代码替换下来所以在使用有副作用的参数时一定要小心。
使用函数的话就不会出现这样的问题
例
#include stdio.hint max(int x, int y)
{return x y ? x : y;
}int main()
{int a 3;int b 5;int m max(a, b);printf(%d\n, m);printf(%d %d\n, a, b);return 0;
}
输出
输出
5
4 6
因为函数传参就是传的a和b过去计算。
2.6 宏和函数对比
属 性#define定义宏函数代 码 长 度 每次使用时宏代码都会被插入到程序中。 除了非常小的宏之外程序的长度会大幅度增长 函数代码只出现于一个地方 每次使用这个函数时 都调用那个地方的同一份代码 执 行 速 度更快 函数调用和返回有额外开销 所以相对慢一些 操 作 符 优 先 级 宏参数的求值是 在所有周围表达式的上下文环境里 除非加上括号 否则邻近操作符的优先级可能会产生 不可预料的后果 所以建议宏在书写的时候多些括号。 函数参数只在函数调用的时候 求值一次 它的结果值传递给函数。 表达式求值结果更容易预测。 带 有 副 作 用 的 参 数 参数可能被替换到宏体中的多个位置 所以带有副作用的参数求值 可能会产生不可预料的结果。 函数参数只在传参的时候 求值一次结果更容易控制。 参 数 类 型 宏的参数与类型无关 只要对参数的操作是合法的 它就可以使用于任何参数类型。 函数的参数是与类型有关的 如果参数的类型不同 就需要不同的函数 即使他们执行的任务是 相同的。 调 试宏是不方便调试的函数是可以逐语句调试的递 归宏是不能递归的函数是可以递归的
总结
宏和函数各有优劣根据实际场景权衡使用。
2.7 命名约定 把宏名全部大写 函数名不要全部大写 3. #undef 这条指令用于移除一个宏定义。 例 我们发现移除宏定义MAX之后再次使用就报错了。
4. 条件编译 我们可以通过使用条件编译根据设定条件屏蔽掉我们不想要的代码。 4.1 单分支条件编译
例
#include stdio.h#define PRINT int main()
{
#ifdef PRINT //还有一个#ifndef是表示PRINT未定义就执行printf(hehe\n);
#endifreturn 0;
}
输出
输出hehe
4.2多分支条件编译
例
#include stdio.h#define PRINT 1int main()
{#if PRINT 1printf(1);
#elif PRINT 10printf(10);
#else printf(???);
#endif return 0;
}输出
输出1
#include stdio.h#define PRINT 10int main()
{#if PRINT 1printf(1);
#elif PRINT 10printf(10);
#else printf(???);
#endif return 0;
}输出
输出10
#include stdio.h#define PRINT 100int main()
{#if PRINT 1printf(1);
#elif PRINT 10printf(10);
#else printf(???);
#endif return 0;
}输出
输出???
4.3 判断是否被定义
例
#include stdio.h#define PRINT int main()
{
#if !defined(PRINT)printf(hehe\n);
#endif#if defined(PRINT)printf(haha\n);
#endifreturn 0;
}
输出
输出haha
当然条件编译也支持嵌套。
在实际中条件编译也有广泛的应用
例
我们可以看一个头文件的源码感受一下 5. 文件包含
5.1 本地文件包含 先在源文件所在目录下查找如果该头文件未找到 编译器就像查找库函数头文件一样在标准位置查找头文件。 5.2 库函数包含 就直接去标准路径下去查找如果找不到就提示编译错误。 5.3 嵌套文件包含
如果在包含头文件的时候出现这样的情况 因为头文件展开后会将所以代码放开
这样就会造成文件内容的重复。
我们可以用条件编译解决这样的问题
例
#ifndef __TEST_H__
#define __TEST_H__
//头文件具体内容
//...
//
#endif
我们用这个条件编译将头文件的内容包起来
当再次调用这个头文件的时候
就会因为 __TEST_H__已经定义过了而不再编译头文件内容。
当然如果你嫌麻烦的话
#pragma once
在头文件中写下这段代码也是同样的效果。
写在最后
以上就是本篇文章的内容了感谢你的阅读。
如果喜欢本文的话欢迎点赞和评论写下你的见解。
如果想和我一起学习编程不妨点个关注我们一起学习一同成长。
之后我还会输出更多高质量内容欢迎收看。