c语⾔fork函数头⽂件_C语⾔模块化编程
单⽚机 C 语⾔模块化编程
下⾯让我们揭开模块化神秘⾯纱,⼀窥其真⾯⽬。
C 语⾔源⽂件 *.c
提到 C 语⾔源⽂件,⼤家都不会陌⽣。因为我们平常写的程序代码⼏乎都在这个 XX.C ⽂件⾥⾯。编译器也是以此⽂件来进⾏编译并⽣成相应的⽬标⽂件。作为模块化编程的组成基础,我们所要实现的所有功能的源代码均在这个⽂件⾥。理想的模块化应该可以看成是⼀个⿊盒⼦。即我们只关⼼模块提供的功能,⽽不管模块内部的实现细节。好⽐我们买了⼀部⼿机,我们只需要会⽤⼿机提供的功能即可,不需要知晓它是如何把短信发出去的,如何响应我们按键的输⼊,这些过程对我们⽤户⽽⾔,就是是⼀个⿊盒⼦。
在⼤规模程序开发中,⼀个程序由很多个模块组成,很可能,这些模块的编写任务被分配到不同的⼈。⽽你在编写这个模块的时候很可能就需要利⽤到别⼈写好的模块的借⼝,这个时候我们关⼼的是,它的模块实现了什么样的接⼝,我该如何去调⽤,⾄于模块内部是如何组织的,对于我⽽⾔,⽆需过多关注。⽽追求接⼝的单⼀性,把
putchar函数超链接颜代码
不需要的细节尽可能对外部屏蔽起来,正是我们所需要注意的地⽅。
C 语⾔头⽂件 *.h
谈及到模块化编程,必然会涉及到多⽂件编译,也就是⼯程编译。在这样的⼀个系统中,往往会有多个
C ⽂件,⽽且每个 C ⽂件的作⽤不尽相同。在我们的 C ⽂件中,由于需要对外提供接⼝,因此必须有⼀些函数或者是变量提供给外部其它⽂件进⾏调⽤。
假设我们有⼀个 LCD.C ⽂件,其提供最基本的 LCD 的驱动函数
LcdPutChar(char cNewValue) ; //在当前位置输出⼀个字符
⽽在我们的另外⼀个⽂件中需要调⽤此函数,那么我们该如何做呢?
头⽂件的作⽤正是在此。可以称其为⼀份接⼝描述⽂件。其⽂件内部不应该包含任何实质性的函数代码。我们可以把这个头⽂件理解成为⼀份说明书,说明的内容就是我们的模块对外提供的接⼝函数或者是接⼝变量。同时该⽂件也包含了⼀些很重要的宏定义以及⼀些结构体的信息,离开了这些信息,很可能就⽆法正常使⽤接⼝函数或者是接⼝变量。但是总的原则是:不该让外界知道的信息就不应该
出现在头⽂件⾥,⽽外界调⽤模块内接⼝函数或者是接⼝变量所必须的信息就⼀定要出现在头⽂件⾥,否则,外界就⽆法正确的调⽤我们提供的接⼝功能。因⽽为了让外部函数或者⽂件调⽤我们提供的接⼝功能,就必须包含我们提供的这个接⼝描述⽂件----即头⽂件。同时,我们⾃⾝模块也需要包含这份模块头⽂件(因为其包含了模块源⽂件中所需要的宏定义或者是结构体),好⽐我们平常所⽤的⽂件都是⼀式三份⼀样,模块本⾝也需要包含这个头⽂件。
下⾯我们来定义这个头⽂件,⼀般来说,头⽂件的名字应该与源⽂件的名字保持⼀致,这样我们便可以清晰的知道哪个头⽂件是哪个源⽂件的描述。
于是便得到了 LCD.C 的头⽂件 LCD.h 其内容如下。
#ifndef _LCD_H_
#define _LCD_H_
extern LcdPutChar(char cNewValue) ;
#endif
这与我们在源⽂件中定义函数时有点类似。不同的是,在其前⾯添加了 extern 修饰符表明其是⼀个外部函数, 可以被外部其它模块进⾏调⽤。
#ifndef _LCD_H_
#define _LCD_H_
#endif
这个⼏条条件编译和宏定义是为了防⽌重复包含。假如有两个不同源⽂件需要调⽤LcdPutChar(char cNewValue)这个函数,他们分别都通过#include “Lcd.h”把这个头⽂件包含了进去。在第⼀个源⽂件进⾏编译时候,由于没有定义过 _LCD_H_ 因此 #ifndef _LCD_H_ 条件成⽴,于是定义_LCD_H_ 并将下⾯的声明包含进去。在第⼆个⽂件编译时候,由于第⼀个⽂件包含时候,已经将_LCD_H_定义过了。因此#ifndef
_LCD_H_ 不成⽴,整个头⽂件内容就没有被包含。假设没有这样的条件编译语句,那么两个⽂件都包含了 extern LcdPutChar(char cNewValue) ; 就会引起重复包含的错误。
不得不说的 typedef
孙侨潞去世怎么回事很多朋友似乎了习惯程序中利⽤如下语句来对数据类型进⾏定义
#define uint unsigned int
#define uchar unsigned char
然后在定义变量的时候 直接这样使⽤
uint g_nTimeCounter = 0 ;
不可否认,这样确实很⽅便,⽽且对于移植起来也有⼀定的⽅便性。但是考虑下⾯这种情况你还会 这么认为
吗?
#define PINT unsigned int * //定义 unsigned int 指针类型
PINT g_npTimeCounter, g_npTimeState ;
那么你到底是定义了两个 unsigned int 型的指针变量,还是⼀个指针变量,⼀个整形变量呢?⽽你的初衷⼜是什么呢,想定义两个unsigned int 型的指针变量吗?如果是这样,那么估计过不久就会到处抓狂错误了。庆幸的是 C 语⾔已经为我们考虑到了这⼀点。typedef 正是为此⽽⽣。为了给变量起⼀个别名我们可以⽤如
下的语句
typedef unsigned int uint16 ; //给指向⽆符号整形变量起⼀个别名 uint16 typedef unsigned int * puint16 ; //给指向⽆符号整形变量指针起⼀个别名 puint16
在我们定义变量时候便可以这样定义了:
uint16 g_nTimeCounter = 0 ; //定义⼀个⽆符号的整形变量 puint16 g_npTimeCounter ; //定义⼀个⽆符号的整形变量的指针
在我们使⽤51单⽚机的 C 语⾔编程的时候,整形变量的范围是16位,⽽在基于32的微处理下的整形变量是32 位。倘若我们在8位单⽚机下编写的⼀些代码想要移植到32位的处理器上,那么很可能我们就需要在源⽂件中到处修改变量的类型定义。这是⼀件庞⼤的⼯作,为了考虑程序的可移植性,在⼀开始,我们就应该养成良好的习惯,⽤变量的别名进⾏定义。
如在8位单⽚机的平台下,有如下⼀个变量定义小程序制作模板材料
uint16 g_nTimeCounter = 0 ;
如果移植32单⽚机的平台下,想要其的范围依旧为16位。可以直接修改 uint16 的定义,即
typedef unsigned short int uint16 ;
这样就可以了,⽽不需要到源⽂件处处寻并修改。
将常⽤的数据类型全部采⽤此种⽅法定义,形成⼀个头⽂件,便于我们以后编程直接调⽤。⽂件名 MacroAndConst.h
其内容如下:
#ifndef _MACRO_AND_CONST_H_
#define _MACRO_AND_CONST_H_
typedef unsigned int uint16;
typedef unsigned int UINT;
typedef unsigned int uint;
typedef unsigned int UINT16;
typedef unsigned int WORD;
typedef unsigned int word;
typedef int int16;
typedef int INT16;
typedef unsigned long uint32;
typedef unsigned long UINT32;
typedef unsigned long DWORD;
typedef unsigned long dword;
typedef long int32;
typedef long INT32;
typedef signed char int8;
typedef signed char INT8;
typedef unsigned char byte;
typedef unsigned char BYTE;
typedef unsigned char uchar;
typedef unsigned char UINT8;
typedef unsigned char uint8;
typedef unsigned char BOOL;大数据培训培训内容
#endif
导航网站源码搜一品资源⾄此,似乎我们对于源⽂件和头⽂件的分⼯以及模块化编程有那么⼀点概念了。那么让我们趁热打铁,将上⼀章的我们编写的 LED 闪烁函数进⾏模块划分并重新组织进⾏编译。
在上⼀章中我们主要完成的功能是 P0⼝所驱动的 LED 以1Hz 的频率闪烁。其中⽤到了定时器,以及 LED 驱动模块。因⽽我们可以简单的将整个⼯程分成三个模块,定时器模块,LED 模块,以及主函数
对应的⽂件关系如下
main.c
Timer.c --?Timer.h Led.c --?Led.h
在开始重新编写我们的程序之前,先给⼤家讲⼀下如何在 KEIL 中建⽴⼯程模板吧,这个模板是我⼀直沿⽤⾄今。
希望能够给⼤家⼀点启发。
下⾯的内容就主要以图⽚为主了。同时辅以少量⽂字说明。我们以芯⽚ AT89S52为例。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论