第八章 编译预处理(二)

二、文件包含和条件编译

C语言一般提供三种预处理功能宏定义、文件包含、条件编译。讲完了"宏定义",这里将要讲解另外两种预处理功能。

1、文件包含

所谓"文件包含"是指一个文件可以将另外一个文件的全部内容包含进来,也就是将另外的文件包含到本文件中,C语言中,通过#include命令来实现。一般形式如下:

#include "文件名"

虽然可以用#include把任何一个其他文件的内容包含到当前文件中,但是在C语言中,最常见的做法还是一些源程序文件(扩展名为.c或者.cpp等)用#include把一些头文件(扩展名.h或者.hpp等)包含进来,如下图:

#include 命令非常有用,可以节省大量的重复劳动,可以把一些公用的内容写成一个文件,如前面讲过的宏定义,就

可以写成一个公文件(一般是一个.h的头文件),然后每个其他的源程序文件都通过#include命令将这个公用文件包含进来。

一般来说#indude都是#inlude一个.h文件,很少出现#include一个.cpp(源程序文件)的情形。

.h文件一般称为头文件,因为h代表head(头)的意思。常把一些宏定义、函数说明,甚至一些公共的#indude命令,外部变量说明(extern)等,都写在一个.h头文件里,然后在源程序文件中再#include这个.h的文件。

例:创建一个head.h,代码为:

#define PI 3.1415926

myProject.cpp文件代码:

#incllude "head.h"

int main(){

    float ftmp;   

    ftmp=2*PI;      //2 * 3.1415926

    printf("ftmp=%f\n",ftmp);  

}

几点说明:

1)一旦修改了head.h这个文件,相当于修改了#include这个.h文件的所有源程序文件(.cpp),在编译的时候就会重新编译,会花费较多的编译时间。

2)一条#include命令只能包含一个文件,如果要#include多个文件,可以使用多条#'include命令。

3)#include一个.h文件,该.h文件内是可以#include其他文件的,非常灵活,也就是说,文件包含是可以嵌套的。

4)#include所包含的文件名可以用"",也可以用<>,它们有什么区别

<>是去系统目录中找所包含文件,所以诸如要包含标准的studio头文件(系统提供的)就用<>,#include<studio. h>

""的含义是首先在当前目录查找要包含的文件,如果找不到,再到系统目录中查找、所以""常用于自己写的一些想被其他文件#include的文件,让系统优先到当前目录中寻找所要包含的文件(因为自己写的这些被包含文件往往会放到当前目录)

2、条件编译

一般情况下,在生成可执行文件的过程中,源程序文件中的所有代码行都参加编译,但有时候希望对其中的一部分内容只在满足定的条件下才进行编译,也就是对一部分内容指定编译的条件也有的时候,希望当满足某条件时对组语句进行编译而当件不满足时编译另外一组语句,这都叫条件编译。

条件编译用得也比较频繁尤其是写一些跨操作系统平台的代码,例如这个代码既要求能在Windows下编译运行,也能在Linux下编译运行,但程序代码中有些特殊的系统调用函数只能在Windows下编译运行或者只能在Linux下编译运行,此时,就有必要使用条件编译。

条件编译有几种形式。

1)形式一

#ifdef 标识符

    程序段1(一堆代码)

#else

    程序段2(一堆代码)

#endif

作用:当标识符被定义过(#define来定义),则对程序段1进行编译,否则对程序段2进行编译当然.。#else程序段2这部分可以没有,此时的形式就变成:

#ifdef 标识符

    程序段1

#endif

在进行程序调试的时候,常常需要输出一些信息,调试完毕后不再输出这些信息。

例:

#define _DEBUG    //不想输出调试信息时可以把这行注释掉

然后在其他一些需要输出调试信息的地方(如main函数中),可以写类似如下代码:

#ifdef _DEBUG

    printf("输出一些变量信息作为调试信息\n");

#endif

2)形式二

#ifndef 标识符

    程序段1

#else

    程序段2

#endif

作用:若标识符未被定义(未用#define来定义),则编译程序段1,否则编译程序段2。与形式一正好相反。

例:

#define RELEASE    
//下面的#ifndef是未定义RELEASE时才成立
//要想达到未定义RELEASE的效果,需要把这行注释掉

然后在其他一些需要输出调试信息的地方(如main函数中),可以写类似如下代码:

#ifndef RELEASE    //如果没定义RELEASE,就执行下面的printf语句

    printf("输出一些变量信息作为调试信息\n");

#endif

3)形式三

#if 表达式

    程序段1

#else

    程序段2

#endif

作用:当指定的表达式值为真(非0)时,就编译程序段1,否则编译程序段2,所以,事先给出一定的条件,就可以使程序代码在不同条件下进行不同程序段的编译。

可以将上述形式扩展一下,引人#elif,如下:

#if 表达式1

    程序段1

#elif 表达式2

    程序段2

#else

    程序段3

#endif

作用:当表达式1值为真(非0)时,就编译程序段1,否则,当表达式2的值为真(非0),编译程序段2,否则编译程序段3。

例:

#define MYPI 1

然后在其他一些需要输出调试信息的地方(如main函数中),可以写类似如下代码:

#if MYPI

    printf("MYPI is defined\n");

#else
    
    printf("MYPI is not defined\n");

#endif

如果不用条件编译,似乎用if语句也可以做这些事情,那么用条件编译的好处是什么?

1)最明显,条件编译可以减少目标程序长度,因为上面5行程序代码,只相当于一行。

printf("MYPI is defined\n");

2)项目开发也许会面临跨平台的问题,为了增加程序代码在各平台之间的可移植性,往往采用条件编译,如果不用条编译就很难解决同一套程序代码在Windows平台下和Linux平台下,都能够在不修改源代码的情况下编译通过,并生成可执行文件的问题。

例:

#if _WIN32        //Windows平台:注意在该平台下,这个宏系统会定义,不需要自己定义

    //这里有一些Windows专用函数

    //WaitForSingleObject(...);

    printf("当前是Windows平台\n");

#elif _Linux_      //Linux平台:注意在该平台下,这个宏系统统会定义,不需要自己定义

    //这里有一些Linux专用函数
    
    //epoll_create(...);

    printf("当前是Linux平台\n");

#else

    //…其他平台(非Windows,非Linux)的处理代码

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值