浅谈C工程中的.c与.h文件

摘要:
在基于C语言的单片机和arm的工程开发中,C语言的模块化特征非常明显。想象一下:你需要在一个项目中使用AD采样模块、LCD模块、串口发送模块、DA控制模块等。你肯定不会选择一个C文件必须是模块化的,这有利于团队开发和提高效率。模块化设计应遵循哪些原则?如何写作。ch文件。1.两者之间的区别。c和。h文件通常是这样说的。c是源文件。h是头文件。通常由创建者

基于C语言的单片机、arm相关的工程开发时,C语言的模块化特点体现的非常明显。试想一下:你的一个工程中需要用到AD采样模块、液晶显示模块、串口发送模块、DA控制模块等。你肯定不会选择在一个.c文件中进行,必须是分模块的,这样才有利于团队开发,提高效率。

那么模块化设计遵循着怎样的原则呢,应该怎么写.c,.h文件呢。

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

通常意义上的说法,.c是源文件,.h是头文件。通常为了创作者为了保护其代码,而把.c文件封装起来,不公开,而将。.h文件提供。此时.h相当于接口,供程序员调用。

但是实际上我们自己编写.h,.c文件时会发现.c与.h文件里面的内容其实并没有什么区别。在.c中写的代码同样可以在.h文件写

2.工程中使用.c,.h文件

总的来说,.h文件有两种使用方法。

方法一:

正是由于1中蓝色部分的描述的原因。我们会发现好多工程中某个模块只有.h文件,而没有.c文件

浅谈C工程中的.c与.h文件第1张

以上图的DSP开发【瑞泰提供的例程为例】其工程中ICETEK-VC5509-EDU.h文件中包含了对12864液晶屏的寄存器地址定义,相关操作函数定义。并没有写相关的.c文件。然后在lcd.c文件中调用ICETEK-VC5509-EDU.h。这样的做法是可行的,为什么可行,上面1中已经讲得很清楚。

但是我们再来思考一个问题。如果这个工程中我又添加了一个ad.c。在ad.c中我们需要用到液晶显示,那么我们得调用ICETEK-VC5509-EDU.h 。如果我们这么做了,工程编译链接会通过吗?

肯定不会,会报define duplicated //重复定义的错误,为什么呢? include "ICETEK-VC5509-EDU.h"相当于把这句话替换成ICETEK-VC5509-EDU.h中的内容,而ICETEK-VC5509-EDU.h中对液晶的寄存器都进行了定义,初始化,函数都已经定义了。你在两个文件中引用ICETEK-VC5509-EDU.h,肯定会报重复定义的错误。

这种方法适用于单模块,或者某个模块不会被多个.c文件调用

方法二:在.c文件中进行变量,数组,函数的定义,在.h文件中进行变量,数组,函数的声明。

C语言支持的是一处定义,多处声明【这里所讲的声明指的是狭义上的声明,引用声明,即不会进行内存分配】

现在将上述的ICETEK-VC5509-EDU.h分成.c和.h文件

首先在.h文件中开头写上

#ifndef __ICETEK-VC5509-EDU_H 
#define __ICETEK-VC5509-EDU_H //防止重复定义,名字与.c相同
#endif

然后就要进行进一步的操作

(1)宏定义,宏定义是遇到此变量即替换

所以放在.h文件中

如:

// McBSP0  ------------------------------------------------------
#define SPCR0 (*(unsigned int *)0x018c0008)
#define PCR0 (*(unsigned int *)0x018c0024)
#define SPCR01 (*(unsigned int *)0x01900008)
#define SPCR02 (*(unsigned int *)0x0)

(2)函数,函数的定义和声明比较清晰

.h文件进行声明

void InitInterrupt(void);   // 初始化中断
void InitCTR();      // 初始化ICETEK-CTR
void CloseCTR();     // 关闭ICETEK-CTR上各设备

.c文件进行定义

void CloseCTR()
{
    CTRGR=0;     
    CTRLR=0; CTRLR=0x40;
    CTRLR=0x0c0;
 LCDCMD(LCDCMDTURNOFF); 
 dbClearKey=CTRCLKEY;
 LBDS=0;
}

这样就可以实现多个.c文件加.h头文件,而不会导致重复定义的问题。

(3)数组等变量

变量的声明和定义在单个文件时好像都不怎么区分的。

变量的声明:指明变量名,变量类型。

变量的定义:指名变量名,变量类型,分配内存空间。

eg int  a; //定义

extern int a; //声明

如果进行了赋值,则肯定是定义

extern int a=0; //定义

所以在.h文件中:

extern unsigned char ledbuf[8],ledx[8];
extern unsigned char dbClearKey;
extern unsigned char ledkey[10][8];
extern unsigned int music[nMusicNumber][2];

//变量声明

.c文件:

unsigned int pwm[8]={ 0x86,0x87,0x83,0x8b,0x89,0x8d,0x8c,0x8e };
//变量必须要定义
unsigned char dbClearKey; //必须要定义
unsigned  char ledbuf[8];
unsigned char ledx[8];

在这地方还是有个疑问的,在.h文件中如果不加extern 编译也是可以通过的,那么unsigned char ledbuf[8]也能表示声明。【.h文件是先被加载进.c文件,所以.h中unsigned  char ledbuf[8]是最先执行的。为什么表示的是声明呢】

免责声明:文章转载自《浅谈C工程中的.c与.h文件》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇oracle建表Gulp插件笔记下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

c语言获取linux的CPU、内存、IO、磁盘、网速(本机编译通过)

代码: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define MAXBUFSIZE 1024 #define WAIT...

C++编译遇到参数错误(cannot convert parameter * from 'const char [**]' to 'LPCWSTR')

转:http://blog.sina.com.cn/s/blog_9ffcd5dc01014nw9.html 前面的几天一直都在复习着被实习落下的C++基础知识。今天在复习着上次创建的窗口程序时,出现了一个错误,百思不得其解。因为是同样的代码,上次的都能顺利的通过编译,这次自己新建了一个工程结果就有一个错误出现,是在调用Create()函数时,传参数出现问...

lua 调试器(Decoda)

1、http://www.unknownworlds.com/decoda,这个工具可以注入到宿主程序内对lua脚本进行调试。 2、有2种方式对lua进行调试 从Decoda启动宿主程序 a、project菜单中的Settings b、在commond中填入你要运行的宿主程序。点击ok c、用它打开lua脚本设置断点。Decoda 中选择Start D...

Idea 软件使用快捷键归纳01

<1>CTRL+P 方法参数提示 <2>ctrl+/ 单行注释 <3>Ctrl+Alt+MIDEA 重复代码快速重构(抽取重复代码快捷键) <4>alt+enter自我修复,出现红色错误代码的解决方案(注意:光标必须定位在红色错误代码处) 可以实现自动导包 <5>ctrl+alt+L自动格式化代码...

IVR交互式语音应答系统

ZingServ平台IVR子系统介绍 IVR系统的中文译名为"交互式语音应答系统",然而,真正的IVR系统早已超出这种中文译名所描述的功能范围--IVR是一种功能强大的电话自动服务系统。对用户来说,只有理解了这一点,才能真正了解IVR系统的价值;而对产品提供商来说,也只有理解了这一点,才能真正明确产品的应用范围和设计目标。  在ZingServ一体化呼叫中...

C++解析(30):关于指针判别、构造异常和模板二义性的疑问

0.目录 1.指针的判别 2.构造中的异常 2.1 如果构造函数中抛出异常会发生什么? 2.2 如果析构函数中抛出异常会发生什么? 3.令人迷惑的写法 3.1 模板中的二义性 3.2 函数异常声明 4.小结 1.指针的判别 面试问题:编写程序判断一个变量是不是指针。 指针的判别:拾遗: C++中仍然支持C语言中的可变参数函数 C...