C语言头文件组织
一、全局变量单独编写(很值得借鉴)。
一般习惯将不同功能模块放到一个头文件和一个C文件中。
例如是写一些数学计算函数:
[cpp]
//mymath.h
#ifndef _mymath_H
#define _mymath_H
extern int Global_A; //声明必要的全局变量
......
extern void fun(); //声明必要的外部函数
.....
#endif
[cpp]
//mymath.c
#include "mymath.h "
#include <一些需要使用的C库文件>
…
int Global_A; //定义必要的全局变量和函数
void fun();
…
int a,b,c; //定义一些内部使用的全局变量
void somefun();
//函数实现体
void fun()
{
…
}
void somefun()
{
…
}
哪个C文件需要使用只需包含头文件mymath.h就可以了。
但是我认为上面的方法虽然好,但是上面定义全局变量的方式在比较大的工程中引起不便,一个模块与其他模块的数据传递最好通过专有的函数进行,而不要直接通过数据单元直接传递(这是VC++的思想),因此不建议在模块的头文件中声明全局变量;全局变量最好统一定义在一个固定的文件中,所以可以采用下面的方法:
定义一个Globel_Var.C文件来放全局变量,然后在与之相对应的Globel_Var.H文件中来声明全局变量
例如:
[cpp]
//Globel_Var.c
/*******定义本工程中所用到的全局变量*******/
int speed;
int torque;
…
…
…
[cpp]
//Globel_Var.H
/*******声明本工程中所用到的全局变量*******/
extern int speed;
extern int torque;
…
…
这样哪个文件用到这两个变量就可以在该文件的开头处写上文件包含命令;例如aa.C文件要用到speed,toque两个变量,可以在aa.H文件中包含Globel_Var.H文件。
[cpp]
//aa.H文件
#include “Globel_Var.H”
…
extern void fun(); //声明必要的接口函数
…
[cpp]
//aa.c文件
#include “aa.H”//每个程序文件中包含自己的同名头件
int a,b,c; //定义一些本文件内部使用的局部变量
void somefun();
//函数实现体
void fun()
{
int d,e,f; //定义一些本函数内部使用的局部变量
…
}
void somefun()
{
…
}
…
——————————————————————————————————
在bb.c文件中用到aa.c文件中的函数void fun()或变量的文件可以这样写
[cpp]
//bb.H文件
#include “aa.H”
…
extern int fun_1(void);//声明本文件的接口函数
…
[cpp]
//bb.c文件
#include “bb.H”
…
int fun_1(void)
{
…
fun();//调用aa.C文件中的fun()函数
…
}
——————————————————————————————————
在主函数中可以这样写:主文件main没有自己的头文件
[cpp]
//main.c文件
#include<系统库文件>
#include “Globle_Var.H”
#include “aa.H”
#include “bb.H”
…
char fun_2();//声明主文件所定义的函数
int i,j; //定义一些本模块内部使用的局部变量
char k;
…
void main()
{
…
fun();
…
i = fun_1();
…
k = fun_2();
…
}
char fun_2()
{
…
}
——————————————————————————————————
这样即不会报错又可以轻松使用全局变量。
二、如果在全局变量前加入static或者const(隐式为static类型的变量)
如下
[cpp]
// xxxx.h
...
const double PI = 3.1415926;
static void* NULL = 0;
...
//
//这个头文件是可以包含在多个编译单元的。
三、头文件编写参考以下基本的规则
理想的情况下,一个可执行的模块提供一个公开的接口,即使用一个*.h文件暴露接口,但是,有时候,一个模块需要提供不止一个接口,这时,就要为每个定义的接口提供一个公开的接口。在C语言的里,每个C文件是一个模块,头文件为使用这个模块的用户提供接口,用户只要包含相应的头文件就可以使用在这个头文件中暴露的接口。所有的头文件都建议参考以下的规则:
1. 头文件中不能有可执行代码,也不能有数据的定义,只能有宏、类型(typedef,struct,union,menu),数据和函数的声明。
例如以下的代码可以包含在头文件里:
[cpp]
#define NAMESTRING “name”
typedef unsigned long word;
menu{ flag1,flag2};
typedef struct
{
int x;
int y;
}Piont;
extent Fun(void);
extent int a;
全局变量和函数的定义不能出现在*.h文件里。例如下面的代码不能包含在头文件:
[cpp]
int a;
void Fun1(void)
{
a++;
}
2. 头文件中不能包本地数据(模块自己使用的数据或函数,不被其他模块使用)。
这一点相当于面向对象程序设计里的私有成员,即只有模块自己使用的函数,数据,不要用extern在头文件里声明,只有模块自己使用的宏,常量,类型也不要在头文件里声明,应该在自己的*.c文件里声明。
3. 含一些需要使用的声明。在头文件里声明外部需要使用的数据,函数,宏,类型。
4. 防止被重复包含。使用下面的宏防止一个头文件被重复包含。
[cpp]
#ifndef MY_INCLUDE_H
#define MY_INCLUDE_H
<头文件内容>
#endif
四、头文件编写参考更多的规则(暂时只能理解1、2、3、4)
有一些头文件是为用户提供调用接口,这种头文件中声明了模块中需要给其他模块使用的函数和数据,鉴于软件质量上的考虑,处理参考以上的规则,用来暴露接口的头文件还需要参考更多的规则:
1. 一个模块一个接口,不能几个模块用一个接口。
2. 文件名为和实现模块的c文件相同。abc.c--abc.h
3. 尽量不要使用extern来声明一些共享的数据。因为这种做法是不安全的,外部其他模块的用户可能不能完全理解这些变量的含义,最好提供函数访问这些变量。
4. 尽量避免包含其他的头文件,除非这些头文件是独立存在的。这一点的意思是,在作为接口的头文件中,尽量不要包含其他模块的那些暴露*.C文件中内容的头文件,但是可以包含一些不是用来暴露接口的头文件。
5. 不要包含那些只有在可执行文件中才使用的头文件,这些头文件应该在*.c文件中包含。这一点如同上一点,为了提高接口的独立性和透明度
6. 接口文件要有面向用户的充足的注释。从应用角度描述个暴露的内容。
7. 接口文件在发布后尽量避免修改,即使修改也要保证不影响用户程序。
五、多个代码文件使用一个接口文件(暂时不能完全理解)
这种头文件用于那些认为一个模块使用一个文件太大的情况。对于这种情况对于这种情况在参考上述建议后,也要参考以下建议。
1. 多个代码文件组成的一个模块只有一个接口文件。因为这些文件完成的是一个模块。
2. 使用模块下文件命名 <系统名> <模块名命名>
3. 不要滥用这种文件。
4. 有时候也会出现几个*.c文件用于共享数据的*.h文件,这种文件的特点是在一个*.c文件里定义全局变量,而在其他*.c文件里使用,要将这种文件和用于暴露模块接口的文件区别。
5. 一个模块如果有几个子模块,可以用一个*.h文件暴露接口,在这个文件里用#include包含每个子模块的接口文件。
还有一种头文件,说明性头文件,这种头文件不需要有一个对应的代码文件,在这种文件里大多包含了大量的宏定义,没有暴露的数据变量和函数。这些文件给出以下建议:
1. 包含一些需要的概念性的东西.
2. 命名方式,定义的功能.h
3. 不包含任何其他的头文件.
4. 不定义任何类型.
5. 不包含任何数据和函数声明.
上面介绍了C头文件的一些建议,下面介绍C代码文件*.c文件的一些建议,*.c文件是C语言中生成汇编代码和机器码的内容,要注意以下建议:
1.命名方式 模块名.c
2,用static修饰本地的数据和函数。
3,不要使用externa。这是在*.h中使用的,可以被包含进来。
4,无论什么时候定义内部的对象,确保独立与其他执行文件。
5,这个文件里必须包含相应功能函数。
结束语:上面介绍了一些C文件组织的建议,用于提高C语言项目的质量,在以后的C项目组织中,学习面向对象和COM的思想,将这些思想加入到C程序中,能够写出更高质量的代码。上面的建议在具体的项目里应该灵活运用。另外,C工程中经常有一些汇编代码文件,这些文件也要使有*.h头文件暴露其中的数据和函数,以便其他*.c文件包含使用。
摘自:中国IT实验室。