C语言头文件组织
一、全局变量单独编写(很值得借鉴)。
一般习惯将不同功能模块放到一个头文件和一个C文件中。
例如是写一些数学计算函数:
//mymath.h
#ifndef _mymath_H
#define _mymath_H
extern int Global_A; //声明必要的全局变量
......
extern void fun(); //声明必要的外部函数
.....
#endif
//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文件中来声明全局变量
例如:
——————————————————————————————————
//Globel_Var.c
/*******定义本工程中所用到的全局变量*******/
int speed;
int torque;
…
…
…
——————————————————————————————————
//Globel_Var.H
/*******声明本工程中所用到的全局变量*******/
extern int speed;
extern int torque;
…
…
——————————————————————————————————
这样哪个文件用到这两个变量就可以在该文件的开头处写上文件包含命令;例如aa.C文件要用到speed,toque两个变量,可以在aa.H文件中包含Globel_Var.H文件。
——————————————————————————————————
//aa.H文件
#include “Globel_Var.H”
…
extern void fun(); //声明必要的接口函数
…
//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()或变量的文件可以这样写
//bb.H文件
#include “aa.H”
…
extern int fun_1(void);//声明本文件的接口函数
…
//bb.c文件
#include “bb.H”
…
int fun_1(void)
{
…
fun();//调用aa.C文件中的fun()函数
…
}
——————————————————————————————————
在主函数中可以这样写:
主文件main没有自己的头文件
//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类型的变量)
如下
// xxxx.h
...
const double PI = 3.1415926;
static void* NULL = 0;
...
//
这个头文件是可以包含在多个编译单元的。
三、头文件编写参考以下基本的规则
理想的情况下,一个可执行的模块提供一个公开的接口,即使用一个*.h文件暴露接口,但是,有时候,一个模块需要提供不止一个接口,这时,就要为每个定义的接口提供一个公开的接口。在C语言的里,每个C文件是一个模块,头文件为使用这个模块的用户提供接口,用户只要包含相应的头文件就可以使用在这个头文件中暴露的接口。所有的头文件都建议参考以下的规则:
1. 头文件中不能有可执行代码,也不能有数据的定义,只能有宏、类型(typedef,struct,union,menu),数据和函数的声明。
例如以下的代码可以包含在头文件里:
#define NAMESTRING “name”
typedef unsigned long word;
menu{ flag1,flag2}; typedef struct
{
int x;
int y;
}Piont; extent Fun(void);
extent int a;
全局变量和函数的定义不能出现在*.h文件里。例如下面的代码不能包含在头文件:
int a;
void Fun1(void)
{
a++;
}
2. 头文件中不能包本地数据(模块自己使用的数据或函数,不被其他模块使用)。
这一点相当于面向对象程序设计里的私有成员,即只有模块自己使用的函数,数据,不要用extern在头文件里声明,只有模块自己使用的宏,常量,类型也不要在头文件里声明,应该在自己的*.c文件里声明。
3. 含一些需要使用的声明。在头文件里声明外部需要使用的数据,函数,宏,类型。
4. 防止被重复包含。使用下面的宏防止一个头文件被重复包含。
#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文件包含使用。
转自:http://www.2cto.com/kf/201109/104897.html
点击打开链接
C语言头文件组织的更多相关文章
- C语言头文件组织与包含原则
转自:http://www.cnblogs.com/clover-toeic/p/3728026.html 说明 本文假定读者已具备基本的C编译知识. 如非特殊说明,文中“源文件”指*.c文件,“头文 ...
- C语言头文件
最近在工作当中遇到了一点小问题,关于C语言头文件的应用问题,主要还是关于全局变量的定义和声明问题.学习C语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深入的思考过.概念上还是比 ...
- C语言头文件的使用(转载)
C语言头文件的使用 ——by janders 转载请注名作者和出处,谢谢! C语言中的.h文件和我认识由来已久,其使用方法虽不十分复杂,但我却是经过了几个月的“不懂”时期,几年的“一知半解”时期才逐渐 ...
- [转载]C语言头文件的作用
最近在工作当中遇到了一点小问题,关于C语言头文件的应用问题,主要还是关于全局变量的定义和声明问题.学 习C语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深入的思考过.概念上还是 ...
- c语言头文件中定义全局变量的问题
c语言头文件中定义全局变量的问题 (转http://www.cnblogs.com/Sorean/) 先说一下,全局变量只能定义在 函数里面,任意函数,其他函数在使用的时候用extern声明.千万不要 ...
- 嵌入式C语言头文件的建立与使用
如何正确编写 C 语言头文件和与之相关联的 c 源程序文件,这首先就要了解它们的各自功能. 要理解 C 文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程. 一般说来编译器会做以下几 ...
- 51单片机C语言学习笔记6:51单片机C语言头文件及其使用
很多初学单片机者往往对C51的头文件感到很神秘,而为什么要那样写,甚至有的初学者喜欢问,P1口的P为什么要大写,不大写行不行呢?其实这个是在头文件中用sfr定义的,现在定义好了的是这样的 sfr P1 ...
- C++标准库头文件名字和C语言头文件名字的区别
1.C++版本的C标准库头文件,一般是cname,而C语言头文件一般是name.h 2.命名为cname的头文件中定义的名字都是从std中来的,而如果是name.h则不是这样的. 3.与是用name. ...
- C语言头文件、库文件的查找路径
在 程序设计中,文件包含是很有用的.一个大的程序可以分为多个模块,由多个程序员分别编程.有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含命令包含该文件即可使用.这样,可避免在每个 ...
随机推荐
- go中string和slice no-copy转换
在go里面,string和slice的互换是需要进行内存拷贝的,虽然在底层,它们都只是用 pointer + len来表示的一段内存. 通常,我们不会在意string和slice的转换带来的内存拷贝性 ...
- Linux 挂载命令 --mount
1.挂载光盘命令 mount : mount [-t vfstype] [-o options] device dir mount [-t 文件系统] [-o 特殊选项] 设备文件名 挂载点 -t ...
- BOM 窗体相关属性以及页面可见区域的获取方式
1 在IE Safari Oper Chrome 都提供了screenLeft和screenTop属性: screenLeft : 相对于屏幕左边的距离 screenTop : 相对于屏幕上边的距离 ...
- Java---文件夹及文件操作
/** * 获取文件夹大小 * @param file File实例 * @return long */ public static long getFolderSize(java.io.File f ...
- 1228.1——计算器(未使用MVC设计模式)
#import "ViewController.h"typedef enum{ kStausNum, kStausOperation}kStaus; typedef e ...
- NPOI通过DataTable导出和读取Excel
Excel导入及导出问题产生: 从接触.net到现在一直在维护一个DataTable导出到Excel的类,时不时还会维护一个导入类.以下是时不时就会出现的问题: 导出问题: 如果是asp.net,你得 ...
- OpenCV——常用函数查询
1.cvLoadImage:将图像文件加载至内存: 2.cvNamedWindow:在屏幕上创建一个窗口: 3.cvShowImage:在一个已创建好的窗口中显示图像: 4.cvWaitKey:使程序 ...
- ubuntu sendmail
一.安装 ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmail先要安装两个包. 必需安装的两个包: 代码 sudo apt-get install sendmail ...
- Lucene学习总结之五:Lucene段合并(merge)过程分析
一.段合并过程总论 IndexWriter中与段合并有关的成员变量有: HashSet<SegmentInfo> mergingSegments = new HashSet<Segm ...
- 自动运行native2ascii 命令的Bat文件的编写
使用eclipse开发,对于.properties文件的国际化,如果不使用插件对文件进行转码,则需要使用native2ascii命令自行对文件进行转码. 为了更方面的执行此操作,我将该 ...