(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");
}