.h文件與.c文件的基本寫法
時間:2018-09-29 來源:未知
這段時間發現大多C語言的初學者,都會被一個問題困擾,那就是.c源文件和.h頭文件到底應該都寫什么?例如:int fd_gprs,這個整型全局變量,是應該寫到.c文件,還是.h文件中,等等。我們這里就簡單說明下,.h頭文件和.c源文件都應該寫什么。
在C語言編程中,我們會將要實現的應用寫成.c文件;系統級的應用,我們會寫成含有main函數的.c文件,來實現系統級的函數調用,已達成我們所要的功能;具體的各個功能模塊,我們習慣寫成單獨的.c文件,然后在主程序main函數之前,會include到所需模塊的.h頭文件中。這樣會使軟件組織結構清晰明了,便于各個模塊的調試工作,提高了工作效率。
那么對于初學者應該明白,.h文件應該寫些什么?
(1).h頭文件
H文件中一般是聲明,包括:變量聲明、宏定義、枚舉聲明、結構體聲明、函數聲明等。.
H頭文件是對該模塊(.c文件)接口的聲明,接口包括該模塊提供給其他模塊調用的外部函數以及外部全局變量。其他模塊訪問這些外部定義的變量和函數都需要在.h文件中冠以extern關鍵字聲明;模塊(.c文件)內的函數和全局變量一般需要在.c文件開頭冠以static關鍵字聲明。
所以說永遠不要在.h文件中定義變量,但可以聲明變量。
如果其他模塊想要調用該模塊的變量和函數,直接包含該模塊的頭文件即可。
例子1:(sqlite_interface.h頭文件)
#ifndef _SQLITE_INTERFACE_H_
#define _SQLITE_INTERFACE_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文件名的定義好與當前模塊的意義有直接關聯。
[2]:C文件中的內容都是與當前模塊相關的內容。
[3]:將不同的代碼寫到不同的.c文件中,便于代碼的管理
例子2:(sqlite_interface.c源文件)
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite_interface.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");
}

