一、全局變量單獨編寫(很值得借鑒)。
一般習慣將不同功能模塊放到一個頭文件和一個C文件中。
例如是寫一些數學計算函數:
[cpp]
//mymath.h
#ifndef _mymath_H
#define _mymath_H
extern int Global_A; //聲明必要的全局變量
......
extern void fun(); //聲明必要的外部函數
.....
#endif
//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()
{
…
}
//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;
…
…
…
//Globel_Var.c
/*******定義本工程中所用到的全局變量*******/
int speed;
int torque;
…
…
…——————————————————————————————————
[cpp]
//Globel_Var.H
/*******聲明本工程中所用到的全局變量*******/
extern int speed;
extern int torque;
…
…
//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(); //聲明必要的接口函數
…
//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()
{
…
}
…
//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);//聲明本文件的接口函數
…
//bb.H文件
#include “aa.H”
…
extern int fun_1(void);//聲明本文件的接口函數
…[cpp]
//bb.c文件
#include “bb.H”
…
int fun_1(void)
{
…
fun();//調用aa.C文件中的fun()函數
…
}
//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()
{
…
}
//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;
...
//
// 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;
#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++;
}
int a;
void Fun1(void)
{
a++;
}
2. 頭文件中不能包本地數據(模塊自己使用的數據或函數,不被其他模塊使用)。
這一點相當於面向對象程序設計裡的私有成員,即只有模塊自己使用的函數,數據,不要用extern在頭文件裡聲明,只有模塊自己使用的宏,常量,類型也不要在頭文件裡聲明,應該在自己的*.c文件裡聲明。
3. 含一些需要使用的聲明。在頭文件裡聲明外部需要使用的數據,函數,宏,類型。
4. 防止被重復包含。使用下面的宏防止一個頭文件被重復包含。
[cpp]
#ifndef MY_INCLUDE_H
#define MY_INCLUDE_H
<頭文件內容>
#endif
#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文件包含使用。