首页 /  技术专区  /  C 宽屏模式 >

条件编译——防止头文件重复包含

1、具体是什么时候会用到条件编译呢?

前面介绍过,大致用在三类地方:

        (1)文件内容被重复include时,去掉重包含的内容

        (2)帮助我们的程序的跨平台

        (3)辅助调试程序

1.1 文件内容被重复include时,去掉重包含的内容

我们以include 头文件来举例介绍,当一个C/C++工程文件写复杂后,在一个.c/.cpp中往往可能会包含十几个头文件,误操作使得同一个头文件重复包含多次,这其实是很正常的。

重复include的话,预编译器处理#include时,会把同一个头文件的内容重复的复制(包含)到.c中,但是我们知道头文件中往往会有struct ***等类型的定义,重复包含后,会导致在同一个.c中有重复的结构体类型定义,我们在第一章就说过,在同一个c文件中不能有重复的类型构体定义,第二阶段编译时,会报重复定义的错误。

但是实际上我们在重复inlcude同一头文件时,并没有报错误,那是因为头文件中加入了#ifndef条件编译,所以说#ifndef其中有一个很重要的用途就是用于防止文件被被重复包含。

(1)以C标准库的头文件stdio.h头为例

1)windows下stdio.h

#ifndef _STDIO_H_
#define _STDIO_H_
//头文件的内容
...
#endif //头文件的结尾

2)Linux下的stdio.h头文件

#ifndef _STDIO_H
#define _STDIO_H       1 
//头文件的内容
...
#endif

疑问:都是stdio.h,但是它们的宏咋不一样呢,一个叫_STDIO_H_,_STDIO_H?

答:如果你仔细阅读这两个stdio.h的话,你会发现这它们里面的内容也不一样,这个并不奇怪,说明它们是由不同团队编写的,一个是用在windows这边,另一个是用在Linux这边。

尽管二者内容有所区别,但是所要实现的事情都是一样的,不然的话你在Liunx下c程序调用了printf函数,结果这个程序到了Windows就不能调用printf了,这就扯淡了。

疑问:宏的头尾怎么都带_呢?

这个是库、OS的标识符的命名习惯,目的是方便识别,因为你一看到带_打头和结尾你就知道,那一定是库、或者OS等标识符。

我们自己的应用程序尽量不要使用这种命名格式,以便与库、OS、框架等的标识符进行区别。

3)使用#ifndef来防止文件重复包含的原理

举例理解,比如:

a.c

#include <stdio.h>
#include <stdio.h>

int main()
{
    ...
}

(a)第一步:预编译器到相关路径找到include所指定的.h文件,然后将所有.h文件中的内容复制到a.c中,替换掉#include <***.h>

注意,重复的.h的内容会被全部复制到.c中。

a.c 

/* stdio.h */
#ifndef _STDIO_H_
#define _STDIO_H_
头文件的所有内容
#endif

/* stdio.h */
#ifndef _STDIO_H_
#define_STDIO_H_
头文件的所有内容
#endif

int main()
{
    ...
}

(b)第二步:处理条件编译,去掉重复的内容

#ifndef的原理很简单,其实就是先重复包含内容,然后再通过#ifndef将重复的内容去掉。

4)说说“防止头文件内容重复宏”的命名

(a)不同的头文件中该宏的宏名是不相同的

如果相同的话,就会导致其它头文件无法正常被包含。

比如:假如stdio.h和stdlib.h中“防止文件内容重复的宏相同的话。

/* stdio.h */
#ifndef _STDIO_H_
#define _STDIO_H_
...
#endif

/* stdlib.h */
#ifndef _STDIO_H_
#define _STDIO_H_
...
#endif

当相同时,第一次包含stdio.h时会定义_STDIO_H_,第二次包含stdlib.h时发现这个宏已经被定义了,导致stdlib.h的内容被丢弃。

(b)如何防止宏名冲突呢?

每个头文件的文件名基本都会不相同的,所以只要你在宏名里面参入文件名,就一定不会重名。

比如对于我们自己写的头文件来说,可以按照如下方式命名这个宏。

比如:

student.h

#ifndef H_STUDENT_H
#define H_STUDENT_H
...
#endif

或者命名为:STUDENT_H_INCLUDED

你也可以有你自己的自定义命名方式,不管你怎么命名,只要名字中包含“文件名”,该宏不会重名。

当然,如果是使用IDE来创建头文件的话,IDE会自动根据你的头文件名字生成该宏,IDE也会提示你,你可以自己修改,但是如果你是使用存文本来编写.h的话,这个宏就需要我们自己定义了。



头像
0/200
图片验证码