#include是不是只能包含头文件?

很多同学往往有一个误解,认为include只能包含头文件,实际上不是的,include可以包含任何文件,
比如包含普通的文本文件,其它.c文件,只不过我们很少包含普通的文本文件和.c文件而已


一、#include 注意事项

为什么不包含普通文本文件

因为在普通文本文件里面,放的一般都不是代码,而是一些普通文本信息,
包含到.c中后一般会导致编译不通过,所以包含普通文本文件的意义不大

为什么不包含其它的.c文件

既然普通文本文件都能包含,自然包含.c文件也可以,但是包含.c文件存在一些个问题

我们都知道在.c中会定义函数,如果.c中有extern属性的函数的话,
不同的.c包含了同一个.c时,会导致函数被重复定义,链接时就会报错

就算加上#ifndef#pragma once也没用,因为它们只能防止在同一文件中多次包含a.c
但是无法防止在不同的.c同时包含同一个a.c

当然,我们只要使用static修饰fun,也就是将fun改为本地的(那么fun就只在本文件有效),
此时倒是可以解决重复定义的问题,但是不管怎么说,我们不建议直接include "***.c",因为这也不是正规操作


二、可不可以将全局变量定义在.h中

当然可以,但是一般只有少数情况会这么做,大多数情况都是定义在.c中,因为放在.h中的话存在一些问题

(1)如果将初始化的全局变量放在.h中的话,可能会带来大麻烦
xxx.h

#ifnedf  H_XXX_H
#define  H_XXX_H

int flag = 100;

#endif

flagextern修饰的,在全局都是可见的,如果这个时候a.cb.cc.c中都包含了xxx.h
这会导致每个.c中都包含了一个int flag = 100;,链接时就会报flag重复定义了,因为有重名的强符号

此时怎么办?可以加static修饰,比如

#ifnedf  H_XXX_H
#define  H_XXX_H

static int flag = 100;

#endif

那么每个.c包含xxx.h时,每个.c中的flag就只在本文件中有效,防止了不同.cflag的冲突,
但是这样也存在问题,如果某个.c中碰巧也定义了一个flag,这也会导致冲突
a.c

include "xxx.h"
int flag = 400;

展开后就变成了
a.c

static int flag = 100;
int flag = 400;

a.c编译为a.o时,也会报错说flag冲突了,因为这两个都是强符号,显然会导致强符号的重名冲突,
所以加static修饰也是不保险的

(2)如果非要将变量放在.h中,只有出现以下描述的情况时,我们才会这么做

那就是希望这个变量时“全局”可见的,能够被其它的.c引用,此时才放到.h中,
而且放到.h中时不能初始化,只能是未初始化的弱符号,因为弱符号是允许重名的

xxx.h

#ifnedf  H_XXX_H
#define  H_XXX_H
...
int flag;
...
#endif

疑问:我就是需要给以一个初始值,怎么办呢?

答:此时我们就需要将有初始化的强符号放在.c中,.h中还是只放未初始化的弱符号,
此时这个弱符号其实就变成了强符号的声明

总结:
· 没有特殊情况,不要全局变量放到.h
· 只有当你希望这个变量是全局可见的时候,才放到.h,以方便其它的.c包含
· 放到.h中时一定不能初始化,否则可能会到带来编译麻烦
· 如果非要初始化的,这个初始化只能放在.c中,.h中的弱符号此时就是声明


三、 <> 与 “”

1. 以 <> 包含头文件

1)如何搜寻.h

直接到指定的“系统路径”下查找你要包含的头文件,如果找到就包含,找不到就提示头文件不存在

我们在第一章中就介绍过,通过gcc -v的详细信息就可以查看系统路径有哪些,
这些系统路径属于“原生”系统路径,也就是由编译器内定的系统路径

2)我们自己能不能把某个路径变成系统路径呢?

可以,只需要给编译命令指定相应选项即可,比如以gcc为例,通过-I选项即可实现,比如:

gcc -I /home/zxf/Desktop/my_include ***.c ***.c

注意:指定的路径也可以是相对路径,而且-I /home/zxf/Desktop/my_include也可以放到最后面,
比如:

gcc ***.c ***.c -I /home/zxf/Desktop/my_include

可以通过 -v 查看是否将路径加入

gcc -I ./my_include/ helloworld.c -v

疑问:如果要好几个路径的话,怎么办?

答:很简单,比如:

gcc -I /home/zxf/Desktop/my_include  -I /home/zxf/Desktop/  helloworld.c

2. 以””包含头文件

1)如何搜寻.h

先到程序员自己指定的路径下寻找头文件,如果找不到再到“系统路径”下寻找头文件

程序员自己指定的路径可以是相对路径,也可以是绝对路径。

""方式包含时,可以在""中直接指定.h所在的路径
在实际上的开发中,以上这两种方式都是经常用到,只不过""方式用的可能更多一些

也可以将自己的.h复制编译器内定的系统路径下,此时也可以使用<>包含
但是一般不这么做,因为编译器内定的系统路劲,放的是系统.h文件,我们最好不要污染