C/C++头文件include规则
C++头文件include规则
编译原理基础知识
计算机不能直接识别和执行用高级语言写的指令,必须用编译程序(也称编译器)把C源程序翻译成二进制形式的目标程序,然后再将该目标程序与系统的函数库以及其他目标程序连接起来,形成可执行的目标程序。
编译器的工作过程,一般说来编译器会做以下几个过程:
1.预处理阶段:负责将源程序聚合在一起,将那些称为宏的缩写形式转换为源语言的语句;其中包括查找.h文件,去处理宏,变量,函数声明,嵌套的.h文件包含等,检测依赖关系,进行宏替换,看是否有重复定义与声明的情况发生,最后将那些文件中 所有的东东全部扫描进这个当前的C文件中,形成一个中间“C文件”;
2.编译阶段:经过词法与语法分析器,生成一个类机器语言的中间表示形式作为输出,并生成可重定位的机器代码;
3.链接阶段:解决外部内存地址的问题,将可重定位的目标文件以及库文件链接到一起,形成真正在机器上运行的代码;
4.加载阶段:把所有的可执行目标文件放到内存中执行。

头文件的作用
内容参考:C语言中 .h文件和.c文件的区别
理论上来说C文件与h文件里的内容,只要是C语言所支持的,无论写什么都可以的,比如你在h文件中写函数体,只要在任何一个C文件包含此.h文件就可以将 这个函数编译成目标文件的一部分(编译是以C文件为单位的,如果不在任何C文件中包含此.h文件的话,这段代码就形同虚设),你可以在C文件中进行函数声 明,变量声明,结构体声明,这也不成问题!!!那为何一定要分成h文件与C文件呢?又为何一般都在h文件中进行函数,变量声明,宏声明,结构体声明呢?而 在C文件中去进行变量定义,函数实现呢??原因如下:
1.如果在h文件中实现一个函数体,那么如果在多个C文件中引用它,而且又同时编译多个C文件,将其生成的目标文件连接成一个可执行文件,在每个引用此h 文件的C文件所生成的目标文件中,都有一份这个函数的代码,如果这段函数又没有定义成局部函数,那么在连接时,就会发现多个相同的函数,就会报错;
2.如果在h文件中定义全局变量,并且将此全局变量赋初值,那么在多个引用此h文件的C文件中同样存在相同变量名的拷贝,关键是此变量被赋了初值,所以编 译器就会将此变量放入DATA段,最终在连接阶段,会在DATA段中存在多个相同的变量,它无法将这些变量统一成一个变量,也就是仅为此变量分配一个空 间,而不是多份空间,假定这个变量在h文件没有赋初值,编译器就会将之放入BSS段,连接器会对BSS段的多个同名变量仅分配一个存储空间;
3.如果在C文件中声明宏,结构体,函数等,那么我要在另一个C文件中引用相应的宏,结构体,就必须再做一次重复的工作,如果我改了一个C文件中的一个声 明,那么又忘了改其它C文件中的声明,这不就出了大问题了,程序的逻辑就变成了你不可想象的了,如果把这些公共的东东放在一个头文件中,想用它的C文件就 只需要引用一个就OK了!!!这样岂不方便,要改某个声明的时候,只需要动一下h文件就行了;
4.在h文件中声明结构体,函数等,当你需要将你的代码封装成一个库,让别人来用你的代码,你又不想公布源码,那么人家如何利用你的库呢?也就是如何利用 你的库中的各个函数呢??一种方法是公布源码,别人想怎么用就怎么用,另一种是提供头文件,别人从头文件中看你的函数原型,这样人家才知道如何调用你写的 函数,就如同你调用printf函数一样,里面的参数是怎样的??你是怎么知道的??还不是看人家的头文件中的相关声明啊!!!当然这些东东都成了C标 准,就算不看人家的头文件,你一样可以知道怎么使用.
一般头文件的include方法
内容参考:C/C++头文件的引用问题(#include使用)

对于一个工程(如下):
在base中包含:func3.h,func3.c,文件夹main和文件夹func4;
在main中包含:main.c,func1.h,func1.c和文件夹func2;
在func2中包含:func2.h和func2.c;
在func4中包含:func4.h和func4.c。
因此:
Main.c 中需要引用头文件 func1.h:处于同一文件夹下
#include “func1.h”(直接引用)
Main.c 中需要引用头文件func2.h:fun2.h处于main的平行子文件夹下
#include “func2\func2.h”(文件夹func2后再引用)
Mian.c 中需要引用头文件func3.h:func3.h处于main的上级文件夹下
#include “…\func3.h”(…后再引用)
Mian.c 中需要引用头文件func4.h:func4.h处于main的上级文件夹的下一级文件夹下
#include “…\func4\func4.h”(…和func4后再用)
Android.bp方式编译代码头文件include方法
在android build系统中,通常使用Android.bp和Android.mk进行module的定义,进而对cpp进行编译,例如:
//system/tools/hidl/Android.bp hidl-gen
cc_binary_host {
name: "hidl-gen",
defaults: ["hidl-gen-defaults"],
srcs: ["main.cpp"],
static_libs: [
"libbase",
"libcrypto",
"libhidl-gen",
"libhidl-gen-ast",
"libhidl-gen-hash",
"libhidl-gen-host-utils",
"libhidl-gen-utils",
"libjsoncpp",
"liblog",
],
}
hidl-gen的src为同级目录下的main.cpp,其头文件include代码如下:
//system/tools/hidl/main.cpp
#include "AST.h"
#include "Coordinator.h"
#include "Interface.h"
#include "Scope.h"
#include <android-base/logging.h>
#include <hidl-hash/Hash.h>
#include <hidl-util/FQName.h>
#include <hidl-util/Formatter.h>
#include <hidl-util/StringHelper.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <vector>
system/tools/hidl目录树:
├── Android.bp
├── AST.cpp
├── AST.h
├── Coordinator.cpp
├── Coordinator.h
├── hashing
│ ├── Android.bp
│ ├── Hash.cpp
│ └── include
│ └── hidl-hash
│ └── Hash.h
├── host_utils
│ ├── Android.bp
│ ├── Formatter.cpp
│ ├── include
│ │ └── hidl-util
│ └── StringHelper.cpp
├── Interface.cpp
├── Interface.h
├── Location.cpp
├── Location.h
├── main.cpp
├── utils
│ ├── Android.bp
│ ├── FqInstance.cpp
│ ├── FQName.cpp
│ └── include
│ └── hidl-util
│ ├── FqInstance.h
│ └── FQName.h
│ ├── FqInstance.h
│ └── FQName.h
│ ......
以main.cpp的头文件#include <hidl-hash/Hash.h>为例:
<hidl-hash/Hash.h>头文件的代码实现在hashing/Hash.cpp中,而Hash.cpp被编译为libhidl-gen-hash.so被hidl-gen链接,即hidl-gen通过hidl-gen/Hash.h头文件访问libhidl-hash.so库中Hash.cpp的代码实现。
libhidl-gen-hash的定义在system/tools/hidl/hashing/Android.bp中:
cc_library {
name: "libhidl-gen-hash",
host_supported: true,
defaults: ["hidl-gen-defaults"],
srcs: ["Hash.cpp"],
export_include_dirs: ["include"],
shared_libs: [
"libbase",
"libcrypto",
"libssl",
],
}
export_include_dirs导出system/tools/hidl/hashing/include,因此hidl-gen在依赖libhidl-gen-hash时,就获得了system/tools/hidl/hashing/include这个路径,只需要以此为相对路径寻找头文件就可以了,即<hidl-hash/Hash.h>.
因此使用Android.bp进行module定义,所依赖的头文件有相对应的库实现时,头文件include可以以库的export_include_dirs为相对路径进行头文件include,soong编译系统会对include路径进行内部转换,但如果使用gcc直接编译main.cpp,会发生报错的情况。
更多推荐

所有评论(0)