(1).h標頭檔案
h檔案中一般是宣告,包括:變數宣告、巨集定義、列舉宣告、結構體宣告、函式宣告等。.
h標頭檔案是對該模組(.c檔案)介面的宣告,介面包括該模組提供給其他模組呼叫的外部函式以及外部全域性變數。其他模組訪問這些外部定義的變數和函式都需要在.h檔案中冠以extern關鍵字宣告;模組(.c檔案)內的函式和全域性變數一般需要在.c檔案開頭冠以static關鍵字宣告。
所以說永遠不要在.h檔案中定義變數,但可以宣告變數。
如果其他模組想要呼叫該模組的變數和函式,直接包含該模組的標頭檔案即可。
例子1:(sqlite_inte***ce.h標頭檔案)
#ifndef _sqlite_inte***ce_h_
#define _sqlite_inte***ce_h_
#include "include/sqlite3.h"
#include "fs4412_mpu6050.h" //此檔案是mpu6050的驅動程式檔案
#define sqlite_open "/mysqlite.db"
struct data
int adc;
union mpu6050_data env_all;
extern int create_table(void);
extern int init_table_env(void);
extern int set_env(int val, int no);
extern void update_env(struct data env);
#endif
(2).c原始檔
上面說到所有的宣告應該寫到.h檔案中,.c檔案中應該寫變數的定義,函式的實現;同時一般在.c檔案內部使用的全域性變數,會冠以static。
為什麼要這樣做呢?不能把變數定義在.h檔案中,函式實現在.h檔案中。
理由:[1]:如果在.h標頭檔案中定義乙個全域性變數,並將此全域性變數賦初值,那麼多個.c檔案引用此.h標頭檔案時,在預處理階段會進行相同變數名的拷貝,即:此全域性變數會存在於多個.c原始檔中,如果在main函式中,對這些.c原始檔進行引用,在編譯連線階段會出現重定義的錯誤。
例如:/tmp/ccvn1qmc.o:(.data+0x0): multiple definition of `a'
/tmp/ccpfykzc.o:(.data+0x0): first defined here
上面指出定義了多個變數『a』,不知道哪個是第乙個定義的變數。
[2]:如果在.h標頭檔案實現乙個函式體,那麼在多個.c檔案中引用它,又同時編譯多個.c檔案,也會出現上面的問題,在連線階段發現有多個相同的函式,進而報錯。
[3]當你需要將自己的原始碼封裝成乙個庫檔案時,讓別人用你的**,又不想公開原始碼,那麼別人怎麼使用你的庫檔案呢?我們可以提供含有函式宣告和結構體的.h標頭檔案,這樣別人才知道怎麼去呼叫你的函式和結構體。
在說幾個細節問題:
[1]:c檔名的定義好與當前模組的意義有直接關聯。
[3]:將不同的**寫到不同的.c檔案中,便於**的管理
例子2:(sqlite_inte***ce.c原始檔)
#include
#include
#include
#include
#include
#include
#include "sqlite_inte***ce.h"
static int callback_val[7];
/*建立資料庫表*/
int create_table(void)
sqlite3* db;
char sql[1024];
int recode;
char *err_msg;
recode = sqlite3_open(sqlite_open, &db);
if(recode != sqlite_ok)
printf("can't open database:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}else
printf("database open ok!\n");
sprintf(sql,"create table env(adc int,gyro_x short,gyro_y short,gyro_z short,accel_x short,accel_y short,accel_z short);");
recode = sqlite3_exec(db, sql, 0, 0, &err_msg);
if(recode != sqlite_ok)
if(strcmp(err_msg, "table env already exists"))
printf("error:%s", err_msg);
sqlite3_close(db);
return 1;
else
printf("table env already exist,so open it ok!\n");
else
init_table_env();
printf("create env ok!\n");
sqlite3_close(db);
return 0;
return 0;
/*初始化環境表*/
int init_table_env(void)
char sql[1024];
sqlite3 *db;
char *err_msg = 0;
int recode;
sprintf(sql, "insert into env values(0, 0, 0, 0, 0, 0, 0)");
recode = sqlite3_open(sqlite_open, &db);
if(recode != sqlite_ok)
printf("can't open database:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
else
recode = sqlite3_exec(db, sql, 0, 0, &err_msg);
if(recode != sqlite_ok)
printf("error:%s", err_msg);
sqlite3_close(db);
return 1;
else
printf("init env ok!\n");
sqlite3_close(db);
return 0;
/*設定某乙個環境資料*/
int set_env(int val, int no)
char sql[1024];
sqlite3 *db;
char *err_msg = 0;
int recode;
switch(no)
case 1:
sprintf(sql, "update env set adc = '%d';", val);
break;
case 2:
sprintf(sql, "update env set gyro_x = '%d';", val);
break;
case 3:
sprintf(sql, "update env set gyro_y = '%d';", val);
break;
case 4:
sprintf(sql, "update env set gyro_z = '%d';", val);
break;
case 5:
sprintf(sql, "update env set accel_x = '%d';", val);
break;
case 6:
sprintf(sql, "update env set accel_y = '%d';", val);
break;
case 7:
sprintf(sql, "update env set accel_z = '%d';", val);
break;
recode = sqlite3_open(sqlite_open, &db);
if(recode != sqlite_ok)
printf("can't open database:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
else
recode = sqlite3_exec(db, sql, 0, 0, &err_msg);
if(recode != sqlite_ok)
printf("error:%s", err_msg);
sqlite3_close(db);
return 1;
else
printf("set env ok!\n");
sqlite3_close(db);
return 0;
/*更新env環境資料*/
void update_env(struct data env)
set_env(env.adc, 1);
set_env((short)env.env_all.gyro.x, 2);
set_env((short)env.env_all.gyro.y, 3);
set_env((short)env.env_all.gyro.z, 4);
set_env((short)env.env_all.accel.x, 5);
set_env((short)env.env_all.accel.y, 6);
set_env((short)env.env_all.accel.z, 7);
printf("update env ok!\n");
C 檔案和 H 檔案如何組織
c 檔案一般包含 必須的標頭檔案 私有巨集定義 私有資料結構 私有變數static宣告 私有函式static宣告 變數定義 和函式定義。h 檔案一般包含 必須的標頭檔案 對外的巨集定義 對外資料結構 對外變數extern宣告 對外函式extern宣告。c 檔案一般實現具體的功能,而 h 檔案一般是 ...
h和 c檔案解析
簡單的說其實要理解c檔案與標頭檔案 即.h 有什麼不同之處,首先需要弄明白編譯器的工作過程,一般說來編譯器會做以下幾個過程 1.預處理階段 2.詞法與語法分析階段 3.編譯階段,首先編譯成純彙編語句,再將之彙編成跟cpu相關的二進位製碼,生成各個目標檔案 obj檔案 4.連線階段,編譯器在編譯時是 ...
c語言中的 c檔案和 h檔案
大神的詳細解讀 傳送門 記錄下一點點自己對兩個檔案的理解 函式宣告可以有多分,但函式定義只能有乙份。所以一般不在標頭檔案裡面定義函式,因為同乙個程式的多個 檔案可能都會包含這個標頭檔案。但c 中的inline函式是個例外,得定義在標頭檔案中。為了能夠擴充套件inline函式的內容,在每個呼叫點上,編...