当前位置: 首页 > backend >正文

【C语言进阶剖析】22.C语言中的条件编译使用分析

文章目录

一、基本概念

二、条件编译的本质

三、#include 的本质

四、条件编译的意义

五、小结


一、基本概念

  • 条件编译的行为类似于 C 语言中的 if...else...
  • 编译是预编译指示命令,用于控制是否编译某段代码

        下面看一段简单的条件编译的代码:

#include <stdio.h>#define C 1int main()
{const char* s;#if( C == 1 )s = "This is first printf...\n";#elses = "This is second printf...\n";#endifprintf("%s", s);return 0;
}

        下面为输出结果: 

         可以输入 gcc -E Test.c -o file.i 命令,看看预编译阶段发生了什么,下面是部分输出结果:

# 2 "Test.c" 2int main()
{const char* s;s = "This is first printf...\n";printf("%s", s);return 0;
}

        可以看到宏定义和条件编译都没有了,由相应内容取而代之。

二、条件编译的本质

  • 预编译器根据条件编译指令有选择的删除代码
  • 编译器不知道代码分支的存在
  • if...else... 语句在运行期进行分支判断
  • 条件编译指令在预编译期进行分支判断
  • 可以通过命令行定义宏
    • gcc -Dmacro=value file.c
    • gcc -Dmacro file.c

        下面看一个通过命令行定义宏的代码:

#include <stdio.h>int main()
{const char* s;#ifdef Cs = "This is first printf...\n";#elses = "This is second printf...\n";#endifprintf("%s", s);return 0;
}

        终端输入 gcc -DC Test.c,输出结果如下:

三、#include 的本质

  • #include 的本质是将已经存在的文件内容嵌入到当前文件中
  • #include 的间接包含同样会产生嵌入文件内容的操作

        这就出现一个问题,间接包含同一个头文件是否会产生编译错误?

         下面就来通过一段代码深入探究:

        global.h:

// global.hint global = 10;

         test.h:

// test.h#include "global.h"const char* NAME = "test.h";char* hello_world()
{return "hello world!\n";
}

        test.c:

#include <stdio.h>
#include "test.h"
#include "global.h"int main()
{const char* s = hello_world();int g = global;printf("%s\n", NAME);printf("%d\n", g);return 0;
}

         编译后编译器报错,global 重定义:

         为什么 global 会重定义呢?下面开始单步编译,输入 gcc -E test.c -o test.i,输出部分结果如下:

# 2 "test.c" 2
# 1 "test.h" 1# 1 "global.h" 1int global = 10;
# 4 "test.h" 2const char* NAME = "test.h";char* hello_world()
{return "hello world!\n";
}
# 3 "test.c" 2
# 1 "global.h" 1int global = 10;
# 4 "test.c" 2int main()
{const char* s = hello_world();int g = global;printf("%s\n", NAME);printf("%d\n", g);return 0;
}

        这样就很明显了,程序先将 test.h 里面的东西复制进 test.c,由于  test.h 里面有一个 include "global.h",就把 int global = 10; 复制过来,然后复制 

const char* NAME = "test.h";

char* hello_world()
{
    return "hello world!\n";
}

        在然后由于test.c 里面又定义一个  #include "global.h",又把  int global = 10; 复制过来,造成了重复定义。

  • 条件编译可以解决头文件重复包含的编译错误
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_//source code#endif

       如果没有定义 header_file.h,则定义,且执行里面的代码;否则,如果定义了,里面的代码就不会执行。

         所以上述代码中可以这么改:

          global.h:

// global.h
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
int global = 10;#endif

          test.h:

// test.h
#ifndef _TEST_H_
#define _TEST_H_#include "global.h"const char* NAME = "test.h";char* hello_world()
{return "hello world!\n";
}#endif

         这样编译就能通过了

 

四、条件编译的意义

  • 条件编译使得我们可以按不同的条件编译不同的代码段,因而可以产生不同的目标代码
  • #if...#else...#endif 被预编译器处理,而 if...else... 语句被编译器处理,必然被编译进目标代码
  • 实际工程中条件编译主要用于以下两种情况:
    • 不同的产品线共用一份代码
    • 区分编译产品的调试版和发布版

        下面看一段产品线区分及调试代码:

        product.h:


#define DEBUG 1
#define HIGH  1

        test.c: 

#include <stdio.h>#include "product.h"#if DEBUG#define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)#else#define LOG(s) NULL#endif#if HIGHvoid f()
{printf("This is the high level product!\n");
}#elsevoid f(){}#endifint main(){LOG("Enter main() ..."); f(); printf("1. Query Information.\n");printf("2. Record Information.\n");printf("3. Delete Information.\n");#if HIGHprintf("4. High Level Query.\n");printf("5. Mannul Service.\n");printf("6. Exit.\n");#elseprintf("4. Exit.\n");#endifLOG("Exit main() ...");return 0;}

        宏 DEBUG 是指产品是调试版还是发布版,调试版为 1,发布版为 0, 宏 HIGH 指的是产品是高端产品还是低端产品,高端产品为 1,低端产品为 0

        如果我们想测试调试版的高端产品,令 DEBUG 为 1,HIGH 为 0 即可:

         同理,我们想测试发布版的低端产品,令 DEBUG 为 0,HIGH为 0 即可:

五、小结

  • 通过编译器命令行能够定义预处理器使用的宏
  • 条件编译可以避免重复包含头同一个头文件
  • 条件编译是在I程开发中可以区别不同产品线的代码
  • 条件编译可以定义产品的发布版调试版
     
http://www.xdnf.cn/news/11483.html

相关文章:

  • Windows Server安装SQL Server 2008 R2
  • euphoria游戏资源_游戏资源合集(一)——乙女游戏篇
  • 有关一级域名二级域名三级域名
  • Broadcast(广播)和BroadcastReceiver(广播接收器)
  • Web 四种常见的POST提交数据方式
  • texttospeech的使用
  • objectArx ---反应器
  • JAVA开发环境配置(保姆式教程)
  • 代码的两种命名方法:驼峰命名、匈牙利命名(优缺点)
  • ADB安装及使用详解(非常详细)从零基础入门到精通,看完这一篇就够了_adb是什么
  • 关于qt缺少xcb问题终极解决办法
  • android 使用SQLite数据库详解
  • HIS系统门急诊医保实时结算接口测试
  • 倍投计算机器在线,2021看图开特马50研究计算倍投【欢迎你】
  • css设置滚动条样式
  • 网络管理与维护基本知识
  • android x86怎么样,Android x86 4.4安装体验(转载)
  • nii与nii.gz格式的关系
  • DWZ简介以及使用
  • csdn是什么
  • Android中GridView解析
  • perl下载与安装教程【工具使用】
  • perl 5.10.0安装包下载
  • Spring AOP全面详解(超级详细)
  • 网络负载平衡(NLB)详解!
  • 虚拟机-安装与使用(详细教程)
  • 智能dns调研及bind9搭建
  • FlashFXP 4.0注册码key 及教程
  • MFC内存映射文件
  • 软件工程专业值得考的8个证书