谈谈头文件
来源:互联网 发布:泛型 java 方法 编辑:程序博客网 时间:2024/05/16 07:23
一、头文件的定义
C语言中常常使用预处理指令#include,把另一个文件的内容复制到源文件当中,被复制的文件就是头文件,其后缀名为.h。
二、头文件的作用
1、在多文件的工程当中,头文件用于全局变量、外部函数的声明,其本身不包含程序的实现代码
例如:
extern int var;//var在某个c文件中定义extern void myFunction(void);//一般情况下,都默认该函数为外部函数,因此可以把extern省略掉
2、用typedef给现有的类型起个新名字
例如:
typedef int ElementType;typedef struct LinkedList{ ElementType value; struct LinkedList *next;}*LinkedList;
3、宏定义
例如:
#define TRUE 1#define FALSE 0
三、头文件的书写方式
如上所述,#include的本质是把头文件的内容拷贝一份到当下的文件当中,因此我们有必要考虑一个问题——如何避免头文件重复包含。
相信很少有人会重复写两次#include "demo.h",但是,更常见的一种重复包含的情况是:有两个头文件first.h和second.h,其中second.h中有#include "first.h"。那么当main.c同时包含first.h和second.h的时候,实际上包含了两次first.h
因此,我们可以通过条件编译来避免重复包含。例如:编写一个头文件demo.h
#ifndef _DEMO_H#define _DEMO_H//宏定义//typedef//全局变量声明//外部函数声明#endif
四、为什么不可以在头文件中定义变量?
1、首先搞清楚编译的过程,流程图如下:
C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf等)
对一个工程编译的时候,每个c文件都是单独编译的并得到对应的.o文件的,紧接着通过连接器把各个.o文件连接起来,最终生成统一的可执行文件。
五、为什么要把函数声明写在头文件?
用一个例子说明:现在有三个文件main.c、test.c、test.h
/*****************main.c*****************/#include <stdio.h>#include "test.h"int main(int argc, char *argv[]){ Function1(); return 0;}/*****************end of main.c*****************//*****************test.c*****************/#include "test.h"void Function1(void){ Function2();}void Function2(void){ printf("Hello world!\n");}/*****************end of test.c*****************//*****************test.h*****************/#ifndef _TEST_H#define _TEST_Hvoid Function1(void);void Function2(void);#endif/*****************end of test.h*****************/
如上面所述,编译器会分别对main.c和test.c编译
在编译main.c的时候,#include "test.h"把Function1()的声明拷贝到当前文件的对应位置,则Function1()的作用域从当前的声明位置一直到c文件末尾。如果去掉该#include语句,则Function1()在调用的时候还不在作用域内,因此编译器会报错。
在编译test.c的时候,如果该c文件中只有一个函数Function2()且main.c只调用Function2()的时候,不写#include "test.h"也是可以的,因为分别编译后得到的main.o和test.o经过连接器的连接,main.o中调用Function2()的时候可以跳转到test.o的Function2()的函数体当中,这个连接过程是连接器自动搜索并实现的。(当然,这是一个不好的编程习惯)
但是,如上面例程所示,当有两个函数Function1()和Function2()的时候,定义的先后不同,如果没有函数声明,则编译器则无法识别Function1()当中的Function2()。所以一般都要养成习惯,函数调用前都声明。
另外,对于Function2(),如果它仅供test.c内定义的函数调用的话,应该定义为static函数,并把test.h中的对应声明去掉,这样就对test.c以外的文件隐藏了它的实现细节,而且避免了不同c文件编写过程中出现的函数同名问题。
六、#include "头文件"一般是放在c文件中还是放在h文件中?
除非h文件当中必须用到某些声明,否则尽量把#include放在c文件中,例如野火STM32开发板资料当中的摄像头例程。
bsp_ov7725.c当中除了包含bsp_ov7725.h外,根据需要还包含了bsp_sccb.h和bsp_ili9341_lcd.h。
而stm32f10x.h却被包含在bsp_ov7725.h中,因为在STM32例程当中,这个库常常用到。更重要的是,在bsp_ov7725.h的内容中包含了下图所示的GPIOA这些标识符,而这些标识符是在stm32f10x.h中声明的,因此stm32f10x.h必须被包含在bsp_ov7725.h中。
1 0
- 谈谈头文件
- 谈谈头文件
- 谈谈自定义头文件
- 谈谈vc如何写dll(封装性,隐藏头文件,私有成员)
- 谈谈vc如何写dll(封装性,隐藏头文件,私有成员)(转)
- 谈谈vc如何写dll(封装性,隐藏头文件,私有成员) .
- 谈谈vc如何写dll(封装性,隐藏头文件,私有成员)
- C++头文件中有定义会造成冲突隐患么? --- 谈谈4个例外情况
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- 头文件
- SDNUOJ1011(斯特灵数)
- Middle-题目105:93. Restore IP Addresses
- Linux下的进度条小程序
- 压缩跟踪Compressive Tracking
- solr服务器搭建
- 谈谈头文件
- swift字符串转double,double转字符串
- Hibernate简介
- Middle-题目106:5. Longest Palindromic Substring
- 3动态规划
- CV codes分类整理集合
- Middle-题目107:61. Rotate List
- Javascript将Form数据转化成Json对象
- 表单中 get与post提交方法的区别