1

Summary

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

2)预编译器根据条件编译指令有选择的删除代码,所以编译器不知道代码分支的存在

3)if else在运行期进行分支判断,一定会被编进目标代码条件编译指令预编译期进行分支判断,可能产生不同的代码段,因此编进目标代码的代码段不确定

4)可以通过命令行定义宏gcc -Dmacro=val file.cgcc -Dmacro file.c

5)#include 本质 是将已经存在的文件内容插入到当前文件中;#include的间接包含同样会产生嵌入文件内容操作。条件编译指令#ifndef _FILE_H_ #define _FILE_H #endif可以解决这种头文件重复包含的错误。

6)条件编译指令只是可以在同一个.c文件中,防止重复包含;如果头文件中有了符号的定义,但是在一个工程的不同c文件里都进行了include,这时候编译这两个文件也会有重复定义的错误(因为两份include在各自的c文件里都定义了一个global,在同一个全局作用域里定义了同名的symbol)。所以,头文件中只声明、不定义

7)工程中的条件编译主要用于:不同的产品线共用一份代码区分编译产品的调试版和发布版

条件编译分析

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

1、条件编译于if...else的区别

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

int main()
{
    #if (C==1)
        printf("if true\n");
    #else
        printf("if false\n");
    #endif    

    return 0;
}
gcc -E test.c -o test.i
// 单步编译后得到的中间文件
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"

int main()
{
        printf("if true\n");
    return 0;
}

分析:

  • 经过预编译期的处理后,得到的中间文件中#if #else #endif都被删掉了,这也说明了上面的预编译器根据条件编译指令有选择的删除代码,所以编译器在拿到中间.i文件后,根本就不知道这些代码分支的存在。
  • 也说明,#if #else #endif是在预编译期进行判断的,而if else是在运行期才会判断
  • // 上述代码中去掉#define C 1
    // 使用命令来定义宏
    gcc -DC=1 test.c
    编译后的运行结果为:if true
    
    gcc -DC test.c
    gcc -DC test.c
    编译后的运行结果为:if true

使用#ifdef #else #endif进行预编译分支判断:

  • #ifdef C
      printf("yes, defined");
    #else
      printf("no, undefined");
    #endif
    
    以上代码进行编译:
    gcc -DC test.c
    输出:yes, defined
    
    gcc test.c
    输出:no, undefined

2、条件编译解决头文件重复包含的编译错误

  • #include 本质 是将已经存在的文件内容插入到当前文件中
  • #include的间接包含同样会产生嵌入文件内容操作。
对以上代码进行单步编译
gcc -E test.c -o test.i
gcc -S test.i -o test.s

分析:单步编译后,在中间.i文件中,global的定义出现了2次,后续的编译过程自然会出现重定义的错误。
image.png

重复包含的解决方式:在头文件test.h和global.h中加上条件编译指令

#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
// SRC
#endif

注意条件编译指令只是可以在同一个.c文件中,防止重复包含;如果头文件中有了符号的定义,但是在一个工程的不同c文件里都进行了include,这时候编译这两个文件也会有重复定义的错误(因为两份include在各自的c文件里都定义了一个global,在同一个全局作用域里定义了同名的symbol)。所以,头文件中只声明、不定义
示例代码:

依旧是上面的test.c test.h global.h,再加一个test2.c文件,其中#include "test.h"
执行:gcc test.c test2.c
输出:multiple definition of 'global'

3、条件编译工程中的应用

  • if else编译器处理,必然被编译进目标代码#if #else #endif预编译器处理,可以按不同的条件编译不同的代码段,因而会产生不同的目标代码
  • 工程中的条件编译主要用于:不同的产品线共用一份代码区分编译产品的调试版和发布版

本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请指正。


bryson
169 声望12 粉丝