.h文件和.c文件的区别

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

}

  • 9
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: static关键字可以用于限制变量和函数的作用域,使其只在当前文件中可见,不能被其他文件访问。在.c文件中,static可以用于定义静态变量和静态函数。静态变量只能在定义它的函数中使用,不会对其他函数产生影响。静态函数只能在定义它的文件中调用,不能被其他文件调用。在.h文件中,static通常用于定义静态函数的声明,以避免与其他文件中的同名函数发生冲突。如果在.h文件中定义静态变量,由于每个包含该头文件的.c文件都会拥有该变量的一个副本,容易造成重复定义错误。因此,通常不建议在.h文件中定义静态变量。 ### 回答2: 在C语言中,可以使用static来限制变量或函数的作用域。在.h文件和.c文件中,static的使用方式有所不同。 在.h文件中,如果我们将函数或变量声明为static,那么它们的作用域将被限制在当前文件中。这意味着在其他文件中无法直接访问这些变量或函数,可以避免命名冲突。通常,在.h文件中不使用static来声明变量,因为.h文件是用于定义接口和声明函数的头文件。 在.c文件中,可以使用static来定义全局或局部变量。当在函数内部使用static关键字声明变量时,该变量的作用域仅限于当前函数。它被称为局部静态变量,每次函数运行后,变量的值都会被保留下来,不会被销毁。这对于需要在函数调用之间保持状态的情况非常有用。 当在函数外部使用static声明变量时,该变量将具有文件作用域,只能在当前.c文件中访问。这对于希望隐藏变量和函数的实现细节的情况非常有用。文件作用域的静态变量在程序的整个运行期间都存在,且在程序开始运行时初始化。 另外,在.c文件中,如果将函数声明为static,则该函数将具有文件作用域,只能在当前.c文件中使用。这意味着其他文件无法直接调用或访问该函数。通过将函数声明为static,可以隐藏函数的实现细节,提高代码的封装性。 综上所述,static关键字可以用于控制变量和函数的作用域,通常在.h文件中避免使用static来声明变量,在.c文件中可以使用static来定义全局或局部变量,并且可以将函数声明为static来隐藏函数的实现细节。 ### 回答3: 在.c和.h文件中,static关键字可以用于函数和变量的声明和定义上。 对于函数,在.c文件中使用static关键字声明一个局部函数,该函数仅在当前文件中可见,不能被其他文件调用。这种方法也称为“静态函数”。在.h文件中不需要使用static关键字声明函数,因为.h文件是用来声明和定义公共函数的。 对于变量,在.c文件中使用static关键字声明一个静态变量,该变量只能在当前文件中访问,其他文件无法访问。这样可以避免命名冲突并增加变量的安全性。在.h文件中一般不会使用static关键字声明变量,因为.h文件是用来声明公共变量的。 总结来说,static关键字在.c文件中用于声明和定义局部函数和局部变量,这些函数和变量只在当前文件中可见。而在.h文件中,不需要使用static关键字声明函数和变量,因为.h文件是用来声明和定义公共函数和变量的,可以被其他文件调用和访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值