重庆网站推广产品企业,可以自己做视频网站吗,传媒公司起名大全,质感设计网站文章目录1 基本概念1.1 代码分析1.2 通过命令行定义宏2 #include 的本质2.1 解决重复包含头文件的问题3 条件编译的应用4 总结1 基本概念
条件编译的行为类似于C语言中的if … else…条件编译是预编译指示指令#xff0c;用于控制是否编译某段代码
比如下图的代码#xff1… 文章目录1 基本概念1.1 代码分析1.2 通过命令行定义宏2 #include 的本质2.1 解决重复包含头文件的问题3 条件编译的应用4 总结 1 基本概念
条件编译的行为类似于C语言中的if … else…条件编译是预编译指示指令用于控制是否编译某段代码
比如下图的代码 上面的 #if、#else、#endif 就是条件编译的构成当然还有其他的样式后面会通过例子详细说明。
1.1 代码分析
如下代码
22-1.c
#include stdio.h#define C 1
int main(){const char* s;#if(C 1)s This is first printf...\n;#else s This is second printf...\n;#endifprintf(%s, s);return 0;
}上述代码编译运行结果为
This is first printf…
上面的代码看起来很简单实际上因为条件编译虽然像if…else 但是它并不像if…else那样在程序运行的时候进行判断而是在预编译器编译的时候就决定了。什么意思呢可以使用预编译指令对上述代码进行预编译当然为了简洁先将1行和第14行需要使用标准库文件的代码注释掉
gcc -E 22-1.c -o 22-1.i生成的预编译文件22-1.i 内容如下
# 1 22-1-lyy.c
# 1 built-in
# 1 command-line
# 1 22-1-lyy.cint main(){const char* s;s This is first printf...\n;return 0;
}可以看到在预编译阶段就已经将条件编译指令处理完了预编译结束后就只剩下条件编译中为真的那段代码。如上面的代码。所以我们可以总结出下面几条规则
预编译器根据条件编译指令有选择的删除代码预编译器不知道代码分支的存在if … else… 在程序的运行期进行判断条件编译指令在预编译期就进行了判断并且将条件为真的代码保留为假的代码删除。
1.2 通过命令行定义宏
补充一点我们还可以通过命令行定义宏而无需再代码中定义如下图所示 如下代码
22-2.c
#include stdio.hint main()
{const char* s;#ifdef Cs This is first printf...\n;#elses This is second printf...\n;#endifprintf(%s, s);return 0;
}如果使用下面的方法编译
gcc 22-2.c -o 22-2.out
运行结果为
This is second printf…
如果使用下面的方法编译
gcc -DC 22-2.c -o 22-2.out 或者 gcc -DC1 22-2.c -o 22-2.out
运行结果为
This is first printf… 我想上面的示例已经足以让我们学会使用命令行定义宏了 2 #include 的本质
这个我们已经熟悉的不能再熟悉的东西了包含头文件有什么玄机
#include 的本质是将已经存在的文件嵌入到当前文件中#include 的间接包含同样会产生嵌入文件的操作这样会导致一个文件包含两个相同的头文件这会产生错误。
比如下图的形式编译会出错 以下面三个代码为例来说明
global.h代码
// global.h
int global 10;test.h
// test.h
#include global.h
const char* NAME test.h;
char* hello_world()
{ return Hello world!\n;
}2-3.c
#include stdio.h
#include test.h
#include global.hint main()
{const char* s hello_world();int g global;printf(%s\n, NAME);printf(%d\n, g);return 0;
}编译运行上述三个代码;
gcc 22-3.c -o 22-3.out./22-3.out 上面错误的行数不一样是因为我个人的代码行数与上面的不一样这个可以忽略 从上面的错误可以看出变量global 重复定义了。很明显我们并没有重复定义。对上述代码进行预编译首先将第1、10、11 行注释掉方便文件内容查看gcc -E 22-3.c -o 22-3.i 得出的预编译文件内容如下
# 1 22-3.c
# 1 built-in
# 1 command-line
# 1 22-3.c# 1 test.h 1# 1 global.h 1int global 10;
# 6 test.h 2const char* NAME test.h;
char* hello_world(){return Hello world!\n;}
# 3 22-3.c 2
# 1 global.h 1int global 10;
# 4 22-3.c 2int main()
{const char* s hello_world();int g global;return 0;
}从上面的预编译文件可以看出
11行和23行中该程序包含了两次 global.h 这个头文件15行和27行中该程序定义了两次global 这个变量导致了变量的重复定义所以代码编译出错。将源代码test.h中包含的global.h文件注释掉重新编译即可。
2.1 解决重复包含头文件的问题
在一个大型软件中重复包含头文件是非常普遍的如果我们一个一个的去找那就会太浪费时间。
使用条件编译是可以解决该问题的。比如将上面的global.h 与test.h改为如下样式
global.h
// global.h
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
int global 10;#endiftest.h
// test.h
#ifndef _TEST_H_
#define _TEST_H_#include global.hconst char* NAME test.h;char* hello_world(){ return Hello world!\n;}#endif改好上面两个文件后重新编译运行代码结果如下 上面改变后的global.h与test.h 只是加了个条件编译指令如果某一头文件被包含过一次再要包含它的时候由于不符合条件编译的条件就不会有后面的代码这样就避免了一个头文件被重复包含的错误。如果不理解回头从头看起多看两遍
3 条件编译的应用
条件编译可以定义软件产品的发布版与调试版 。
可以在代码中使用条件编译来定义需要调试的代码当整个软件产品都调试通过最终需要发布的时候可以直接去掉相关的宏定义或者直接使用命令行的时候不定义调试需要的宏即可就可以使得代码在编译的时候直接删除调试部分的代码而无需自己动手删除。
本部分就不写实验了。
4 总结
条件编译可以使得我们按照不同的条件编译不同的代码片段因而可以产生不同的目标代码通过编译器命令行可以定义预处理器使用的宏条件编译可以避免重复包含同一个头文件多次条件编译可以定义软件产品的发布版和调试版