预处理


1、编译的过程

源码.c->(预处理)->预处理过的.i源文件->(汇编)->汇编文件.S->(编译)->目标文件.o->(链接)->elf可执行程序

    预处理:预处理器

    汇编 :汇编器

    编译 : 编译器

    链接 : 链接器

    预处理就是调用预处理器做一些代码的前期执行动作,使得编译器可以专心只做和编译相关的事情。


2、常见的预处理

    这里介绍常见的预处理的方式,一般为四种。

gcc 中提供了只进行预处理而不进行编译的方法:

gcc -E xx.c -o xx.i

这样就可以从 .i 文件中去学习,去认识预处理。

(1)头文件的包含:#include <> 和 #include""

#include <> : 是在系统或者编译器默认的路径去寻找头文件

#include"" : 在当前的工程目录下去寻找头文件,

包含头文件的真实含义:

    其实就是将 include 包含的头文件,将这个头文件里面的内容在原地进行展开,替换 include 这一行。这些工作,就是由预处理器进行处理。

(2)注释

    自己学习的时候编写的注释,只是给自己查看的,而不是给编译器,所以就在预处理的阶段拿掉所有的的注释。预处理器完成清除所有的注释之后,才交给编译器去编译。

(3)条件编译:#if  #elif  #endif #ifdef

    一般的情况下,源代码都是参加编译的,但是又希望在满足一定的条件下才进行编译,也就是一部分的内容指定编译的条件。

例子1:

例子1:
#if 条件
    // code
#else
    // code
#endif
例子2
#ifdef  条件
    // code
#else
    // code
#endif

 

 

#define DEBUG
int main(int argc, char *argv[])
{
    
#ifdef DEBUG
    printf("DEBUGGING
");
#else
    printf("NOT BUGGING
");
#endif // DEBUG
    printf("OK
");
    while (1);
}
打印输出:
DEBUGGING
OK

    当# ifdef 条件成立的时候,就会执行下面的代码动过;当没有定义,也就是条件不成立则执行 else 的部分。

(4)宏定义

    宏定义代表了一些特定内容的标识符,在预处理的阶段预处理器会将宏定义直接展开为定义的内容。完成的当作,其实就是原封不动展开(做的是文本替换工作)。

    习惯上总是全部用大写的字母来定义宏。

带参:

#define MAX(a,b) ( ((a)>(b)) ? (a) : (b) )

    宏定义传参了,传参的部分都加上括号,最后再添加添加括号。不然会带来宏定义的二义性。

不带参数:

定义一年的秒数:

#define SEC_YEAR    (365*24*60*60UL)

    注意:(1)当出现数字的时候,默认的是 int 类型的,

(2)一年的描述超过了 int 类型的范围,会造成数值的溢出。所以,就需要将数值转为无符号整数。记住需要将 UL 放到括号的内部。

宏定义实现条件编译:

#define DEBUG
#ifdef DEBUG
#define  debug(format,args)   printf(format,args);
#else
#define debug(fromat,args)
#endif // DEBUG
int main(int argc, char *argv[])
{
    
    int a = 1;
    debug("a = %d
",a);
    while (1);
}

    当定义了 DEBUG 的时候,debug 可以进行打印参数,而当没有定义的是则为空。


(5)特殊宏定义

    编译器提供了一些特殊的宏定义,在预编译的阶段将特殊符号进行特换。

__LINE__ : 包含当前的行号

__FILE__: 包含当前的文件名

__DATE__: 包含当前的日期

__TIME__: 包含当前的的时间

__FUNC__ : 包含当前的函数

printf("%s,%s
",__LINE__,__FUNC__);

原文地址:https://www.cnblogs.com/qxj511/p/4942263.html