C语言__预处理(宏定义、文件包含、条件编译)

C语言__预处理(宏定义、文件包含、条件编译)

预处理简单理解

    1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译

    2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号

    3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件

    4.C语言提供的预处理指令主要有:宏定义、文件包含、条件编译

宏定义分类——不带参数的宏定义 和 带参数的宏定义

——不带参数的宏定义

    1.一般形式:#define 宏名 字符串 【例】 #define ABC 10

    2.作用:在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。

    3.使用习惯和注意:宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误;对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作;在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查;宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令;定义一个宏时可以引用已经定义的宏名。

#define PI 3.14
#define R  3.0
#define L  2*PI*R
#define S  PI*R*R
/*
作用范围
/*
#undef PI
/*
之后PI不在进行字符串替换
*/
——带参数的宏定义

1.一般形式:#define 宏名(参数列表) 字符串

2.作用:在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换

3.使用习惯和注意:宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串;带参数的宏在展开时,只作简单的字符和参数的替换,要想计算得确保计算在宏定义中书写正确。

#include <stdio.h>

#define Pow(a) (a) * (a)
#define Pow_1(a) ( (a) * (a) )

int main(int argc, const char * argv[]) {
    int b = Pow(10) / Pow(2);  //  int b = (10) * (10) / (2) * (2);
    int b = Pow_1(10) / Pow(2);  //  int b = ( (10) * (10) ) / ( (2) * (2) );
    
    printf("%d", b);
    return 0;
}

宏定义和函数的区别

    1.宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
    2. 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率

条件编译的概念——在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行)。

    1.基本用法

#if 条件1  //  如果条件1成立,那么编译器就会把#if 与 #elif之间的code1代码编译进去
           //(注意:是编译进去,不是执行,很平时用的if-else是不一样的)
 ...code1...
#elif 条件2  //  如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的code2代码编译进去
 ...code2...
#else  //  如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的code3编译进去
 ...code3...
#endif  //  条件编译结束后,要在最后面加一个#endif,不然后果很严重
注意:#if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才有使用的意义。

    2.其他用法

#if defined(MAX)  //  如果前面已经定义过MAX这个宏,就将code编译进去。
    ...code...
#endif

#if !defined(MAX)  // 如果前面没有定义过MAX这个宏,就将code编译进去。
     ...code...
#endif

            //  #ifdef的使用和#if defined()的用法基本一致
#ifdef MAX  //  如果前面已经定义过MAX这个宏,就将code编译进去。  
    ...code...
#endif

             //  #ifndef又和#if !defined()的用法基本一致
#ifndef MAX  //  如果前面没有定义过MAX这个宏,就将code编译进去。
    ...code...
#endif

文件包含——#include,它可以将一个文件的全部内容拷贝另一个文件中。

    1.一般形式:

                        第1种形式#include <文件名>
                        第2种形式 #include "文件名"

    2.使用注意:

#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如 a.h 包含 b.h,b.h 包含 a.h。

使用#include指令可能导致多次包含同一个头文件,降低编译效率。防止多次包含同一头文件导致效率降低,使用条件编译。

#ifndef _ONE_H_  //  条件编译第一次运行  检查_ONE_H_  是否被宏定义,没有就顺序执行;已经定义了就可以直接跳过
#define _ONE_H_  //  进行宏定义_ONE_H_  

void one();      //  声明函数

#endif           //  结束本次的条件编译

猜你喜欢

转载自blog.csdn.net/z1162565234/article/details/80466842