网站建设服务器,企联网登录,百度游戏风云榜,中国手工加工网免费供货#x1f916;本篇文章主要讲解预处理的知识#xff0c;即使你是小白也可以看的懂#xff0c;若你对预处理有所不解#xff0c;确定不来看看吗#xff1f;#x1f63f; 目录
一.代码运行是的两种环境
二.翻译环境
三.预定义符号
四.#define
1.define 定义宏
2.带有… 本篇文章主要讲解预处理的知识即使你是小白也可以看的懂若你对预处理有所不解确定不来看看吗 目录
一.代码运行是的两种环境
二.翻译环境
三.预定义符号
四.#define
1.define 定义宏
2.带有副作用的宏参数
总结
五.#define定义宏 与函数对比
六.预处理指令
编辑 七.条件编译
八.头文件包含的方式
嵌套文件包含
《高质量C/C编程指南》中的两个问题 一.代码运行是的两种环境 1.翻译环境在这个环境中源代码被转换为可执行的机器指令。 2.执行环境它用于实际执行代码 下面主要讲解翻译环境。
二.翻译环境
从.c 文件到 .exe 文件需要经过编译器的翻译而翻译又分为 编译和链接两个部分 编译又分为三个部分 1.预编译又叫预处理在这个部分主要完成头文件的包含#define的替换注释的删除 2.编译主要完成语法分析词法分析词义分析符号汇总符号包括全局性的变量和函数生成汇编代码 3.汇编生成二进制指令形成符号表符号表是由符号和其地址组成的 链接合并段表合并符号表在这个阶段会发现未定义的函数。 见下图 三.预定义符号 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI C其值为1否则未定义 四.#define
1.define 定义宏 宏的申明方式 #define name( parament-list ) stuff 其中的 parament-list 是一个由逗号隔开的符号表它们可能出现在stuff中。 注意 name 需与后面的括号紧密相连不可以有空格如果有任何空白存在参数列表就会被解释为stuff的一部分。 注意当我们定义宏的时候不要吝啬括号
来看下面一个例子
#define MOD(x,y) x*yint main()
{int m MOD(23,2);printf(%d\n, m);return 0;
}
对初学者来说这段代码的答案很容易被认为式10但事实并非如此因为宏是在预处理阶段先替换掉然后在进行计算所以在没有括号的情况下替换后是这样的23*28所以若是想要得到10这个结果就要加上括号即
#define MOD(x,y) ((x)*(y))
2.带有副作用的宏参数
我们知像是前置 后置这种的运算符是会改变操作数的值属性的那它如果应用到#define 定义的宏中会是怎么样呢
我们来看下面这个例子
#define MAX(x,y) ((x)(y)?(x):(y))int main()
{int a 4;int b 6;int m MAX(a, b);printf(m%d\n, m);printf(a%d b%d\n, a, b);return 0;
}
最后的答案会是多少呢 首先完成宏参数的替换((a)(b)?(a):(b)) 后置是先使用后因为46所以执行后面的 b经过前面的此时a5b7所以先把7赋给m然后b得到b8; 即m7 a5 b8 总结 1.#define 定义的符号需要先原封不动的替换掉所以建议在#define 后面不加 ; 2.#define 定义的宏不要吝啬括号以免出现出乎意料的结果 3.避免使用带有副作用的运算符。 五.#define定义宏 与函数对比 六.预处理指令
所有的预处理指令都是以井号#开头。它必须是第一个非空字符为了增强可读性预处理指令应从第一列开始。下面列出了所有重要的预处理指令 七.条件编译
可以实现将一条语句一组语句编译或者放弃。
常见的条件编译指令 1. #if 常量表达式 //... #endif //常量表达式由预处理器求值。 如 #define __DEBUG__ 1 #if __DEBUG__ //.. #endif 例
int main()
{
#if 1 //如果这个常量表达式为真则执行后面的语句反之则不执行printf(haha\n);
#endifreturn 0;
}
运行结果 2.多个分支的条件编译 #if 常量表达式 //... #elif 常量表达式 注意这里是 elif 而不是else if //... #else //... #endif 例
#define M 10int main()
{
#if M5printf(mafumafu\n);
#elif M10printf(Eve\n);
#elif M7printf(Sou\n);
#elif M2printf(amatsuki\n);
#else printf(soraru);
#endifreturn 0;
}
运行结果 3.嵌套指令 #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 八.头文件包含的方式 1. 双引号式 #include test.h :先在源文件所在目录下查找如果该头文件未找到编译器 就像查找库函数头文件一样在标准位置查找头文件。 如果找不到就提示编译错误。 2.尖括号式 #include stdio.h: 查找头文件直接去标准路径下去查找如果找不到就提示编 译错误。 所以说库里的头文件也可以用 双引号 包含 但并不建议这样做因为双引号包含没有尖括号包含的查找的快。 嵌套文件包含 comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了公共模块。 test.h和test.c使用了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了文件内容的重复。 如何防止这种问题出现
有两种解决方式 1.利用条件编译指令 #ifndef __TEST_H__ //如果没有定义 TEST_H__ 则执行下一句代码 定义 __TEST_H__
#define __TEST_H__
#endif 2.利用预处理指令 #pragma once 《高质量C/C编程指南》中的两个问题 1. 头文件中的 ifndef/define/endif是干什么用的? 防止头文件的重复引用。 2. #include filename.h 和 #include filename.h有什么区别? 文件的查找策略不同。 关于预处理的知识就到此结束了若有错误或是建议欢迎小伙伴们提出 希望小伙伴们能多多支持博主哦你们的支持对我很重要 谢谢你的阅读。