nba球队英文名称和队标:C51模块化的各家说法.

来源:百度文库 编辑:偶看新闻 时间:2024/05/04 07:49:28

 

C51模块化的各家说法

***************************

 

嘿嘿,就是要这样搞,免得被别人用了,那才麻烦。
#ifndef __LCD_H__    //如果未定义__LCD_H__
#define __LCD_H__    //
则定义__LCD_H__
.....                //
声明其它部分
#endif


从这个命名可以推知,该文件叫做lcd.h,如果有一个main.h,它里面使用了include<"lcd.h">,另外还有一个hardware.h,里面也用了include<"lcd.h">,

而在main.c里面,又有include<"main.h">,include<"hardware.h">,那么就会有重复引用了,
在第一个#ifndef __LCD_H__,由于__LCD_H__未定义,所以就在第一个中定义__LCD_H__,并且
声明或者定义一些东西,等遇到第二个#ifndef __LCD_H__,这时__LCD_H__已经被定义,
所以后面的那些东西不声明或者定义,因而就避免了编译时报重复定义的错误.相当于
代码自动判断了前面是否已经引用了该头文件!如果前面已经引用一次,则if--end
面的就不会再被编译了,相当于自动删除了,这样多方便啊.

又由于这个名字很怪,一般程序员几乎不会在其它地方用到,所以就不用担心被别人定义了去。

 

 

***********************

所谓C51的头文件就是.H 文件,它分两种:一种是系统自带得头文件,比如reg51.h stdio.h 等,这类文件在调用是直接在程序的开头用#inlcude <**.h>就可以,系统自动识别;另一种就是自己写得,你需要另建一个文档,以.h为后缀,其中的内容主要是你自己定义得公共变量和函数,以方便不同模块调用,在要用到这些变量合函数的文件开头加上#include <*.h>就可以了!

-------------

bucker:
KeilC51
不是不支持extern,而是不支持对sbit变量的extern声明(sbit类型是C51特殊规定的,非ANSI C数据类型)。

shiphil:
如果只是用Keil C来举例说明C的头文件问题,那么这个例子不适合,因为在AVRC语言(包括绝大多数符合ANSI CC语言)中,是不会有这样的情况的,用extern可以解决工程C文件包含外部变量及函数的问题。

如果真是Keil C中出现这样的问题,那么建议(我以前的做法):外部C文件只有函数及少量局部变量,其他变量用参数传递。没有解决不了的,不要硬性规定在外部C文件中也使用sbit这样的变量。似乎对我那问题也有点提示,头文件中尽量少定义变量,都加上extern

 

------------------

C51编程:.h的头文件里面怎么只有函数声明,而没有具体的函数呢?函数原型去哪儿...

C51编程:.h的头文件里面怎么只有函数声明,而没有具体的函数呢?函数原型去哪儿找?[qinr]  [706次]  2007-8-21

总是找不到原型

·         全局函数的声明,可以在子程序里找到[ddllxxrr] [806次] 2007-8-22 8:30:15

·         如果是库函数的话是找不到原型的,已经打包成lib文件了,只管用就是了。[liy-tj] [552次] 2007-8-23 9:53:04

·         。。。[唐伯猪] [712次] 2007-8-23 9:55:4

·         你的意思是说在cinlude.h的时候需要调用的会自动到lib包里面去取?不需要管原型是么?[qinr] [494次] 2007-8-29 15:46:22

·         yes[interrupt] [724次] 2007-8-29 18:13:09

------------------------

 

C51包含头文件方法

在单片机程序编写过程中使用C51可以很方便的移植,其中从包含头文件的过程中就可以看出其方便之处。比如写了个LCD1602的驱动程序,如果使用汇编语言,则每一次新建立一个工程的时候都要将原来写好的LCD1602驱动程序的那一段拷贝到程序中,这样做比较麻烦,而如果用C51则可以很轻松的解决这个问题。包含头文件的方法可以有两个:

1.将写好的头文件拷贝到当前工程的文件夹下面,然后在源程序里用#include的方法包含进去,假设在这个头文件中定义了某个函数,这样在头文件中定义的函数变可以直接在main()函数中调用了。示例如下:


#include
#include "lcd1602.h"

main()
{
...........
WriteLcdInstr(0x01);//lcd1602.h中已经定义
...........
}

2.上述方法仍然要求每建立一个工程就需要把对应的头文件复制到工程的文件夹里,这样看来仍然是比较麻烦的,这时还有另外一中方法就是将做好的头文件放在一个文件夹中,然后将这个文件夹整体拷贝到..KEIL\C51\INC\下面,以后若需要使用某个头文件,就如使用KEIL自带的头文件一样方便了,在主函数mani()之前有一句#include 就可以在main()中使用其中的函数了。

------------------------------

.h文件是用来声明一些函数用的,C文件是这些函数具体实现的源代码文件,在其他文件中可以用包含头文件的方法来使用这些函数

--------------------------------

 

 

 

 

---------------------

“再一个.c文件中,我包含math.h文件后可以使用数学函数,但是这些数学函数的实体并不在math.h文件中,而应该再.c文件中的,这种调用是怎么实现的呢????”

math.h中只是提供可一些函数的信息。。。。实际代码在预编译代码的库文件中。。。

因为math.h中包含了函数的信息,这个也就回答了你提的为什么“有神么规则是的通过.h中的函数声明就找到这个实体的呢??如果说是默认,那么我如果在两个.c文件中实现了两个不同操作,那会调用那个呢??”比如这样说吧:一个张三一个李四,在这里面说好了,等要叫张三去干活了,张三出去。。而不是李四,否则相反~

还有#include语句只是一个预处理指令。。。

 

库函数中的函数体在编译的时候会加进去,不过你看不见。什么东西都让你看见,编译器厂家只能喝西北风了

--------------------------

在链接时从静态库中复制二进制代码到目标程序中去.
这也是链接器的主要工作.

比如
#include 
void test();
int main(void)
{
    test();
    return 0;
}
这个程序编译是没问题的,但是链接的时候会发生错误.
函数的声明是给编译器看的.声明函数,让编译器知道有这么个函数,在调用的地方生成一些信息.
但是因为没有实现,所以链接器找不到,就发生链接错误.

 

----------------

可能是我没有问清楚,大家的讨论都不是我想要的math.h只是我一个举例,我重新表达一下吧。

我在a.h中声明了函数go(),现在,我编写一个a.c文件,其中includea.h
那么我在a.c中实现了go()函数的实体。

我另外写一个b.c文件,其中需要调用上面的go()函数;我通过includea.h就可以了吗?  他是怎么通过a.h就能找到我写的那个a.c中的go()函数的呢???

---

是这样的。。。1.只要你的头文件a.h中包含有go()函数的相关信息..(比如stdio.h中包含printf(),和scanf()函数一样的道理。。。),预编译代码的库文件中又有关于go()函数的实形代码。。。那么就能在其他的源文件中调用。。。

2. 他是怎么通过a.h就能找到我写的那个a.c中的go()函数的呢???

。。。。。像这些信息都在他的头文件中定义了,你不必钻牛角尖!

编译过程:源代码-编译(得到目标代码.OBJ-链接(比如:printf真正代码放到里面,在先前它只是定义了)-运行。。。

---------------------------

以前我都是在.h头文件中定义函数,然后把.h文件includemain()所在的.c文件,在mian()函数中调用.h中的函数。
最近有朋友告诉我不能这么做,应该把函数声明写在.h中,另外建个.c文件定义具体的函数操作,再把.h文件includemain()所在的.c文件,调用即可。
〉〉〉
不知这个问题怎么处理才好?

你的朋友是对的。
这个问题的关键在于你的方法是适合在小的工程中,不会有多次包含头文件的情况,或者很容易避免这样的情况,如果项目的代码比较多的时候,你的方法就会有比较大的问题。
会出现多个文件同时包含一个。h文件,然后编译的过程就出现重定义,然后你只好吭哧吭哧该代码吧。。。

一个好习惯,除了staticinlineextern函数,正常的函数不要在.h里实现,只是把申明放在h里,实现放在.c里。

函数声明写在.h
另外建个.c文件定义具体的函数操作
再把.h文件includemain()所在的.c文件

 

 

 

*******************************

最近在学模块化编程。要自己写头文件。看了一下别人的头文件,无非就两种。
一种是只有一个.h文件,把函数的定义及函数的具体实现都放在一个.h文件中。
另外一种是一个.c文件,一个.h文件。.c是函数的具体实现,而.h只是定义函数。
这两种谁优谁劣?

>>>>>>>>第二个比第一个稍微好点。
第二个的修改:C文件中定义函数和变量及函数的具体代码,在H文件做变量和函数的声明以及其他的宏定义,不应该涉及具体的代码实现和函数定义等。

-----------------

那我的这句
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
应该放在.c文件中,还是.h文件中呢?还是两个都要放?应为我的.c文件中也要用到uintuchar

>>>>>>>>>放在一个H文件中,被各个C文件调用-

--------------

首先C不是头文件,所谓头文件,英文中是header file,也就是.h文件

------------------

 

hqgboy说:
搞一个公用的头文件,其他模块都是独立的XXOO.C XXOO.H...
每一个XXOO.H都包含公用的头文件。
每一个XXOO.C都包含自己的头文件。
"
我的理解就是:

#define unsigned int uint
#define unsigned char uchar
这类所有c文件都要用到的放在一个公共的.h文件,比如叫public.h
然后后面就是
display.h(这里面要#inculde"public.h")
display.c(
这里面要#include"display.h")
keyscan.h
keyscan.c
然后写一个main.c里面先包含public.h,display.hkeyscan.h然后就可以调用displaykeyscan里面的函数了是吧?
我的理解对吗?

--------------------------------

关于C中的头文件

C(或C++)中的所谓头文件其实就是编译中第一次扫描是所做的文本嵌入。有点类似于宏替代,只不过其被放置在一个独立的文件中而已。

由于头文件可以被多模快引用,因此通常不能将具体变量或函数的实体放入到头文件中定义。否则,若被多模块引用后,便会出现重复定义的问题。另外,由于语法上不限制在同一模块中多处引用同一头文件,因此必须在头文件中加入相关条件编译来防止重复引用。

一般而言,头文件中通常放置的是各种变量类型或函数原型的定义。由于相关定义可以是全局的或局部于某一模块的,因此一般采用树状结构组织相关的头文件。全局头文件处在树根处,然后按模块关系逐级构建相关自树,最终树叶作为具体相关模块的头文件。树的母子关系体现在头文件间的嵌入引用关系(母嵌入在子中)。

----------------

二种
全局变量、模块接口都在h文件里声明
模块的私有变量和函数的声明和定义都放在c文件里
总之就是OOP的思想

 

------------------

同意1213楼。
1. 建立一个总的头文件,它包含所有的头文件。
2. 在每一个.c文件中包含该总的头文件
很省事。
uCOS/II就是这样做的。

 

----

18楼的总头文件的做法往往是为了简化C文件和相关头文件的包含关系,不过我觉得有两个副作用:
1、模块间的层次没能在源文件中清晰体现;
2、只要你改动其中任一个头文件,编译器会重新编译所有源文件。

------------

同意楼上,总头文件虽然简化了书写,但是却导致编译效率的降低,另外不利于程序的阅读。
uCOS/II这样做的好处是你可以把uCOS/II当成一个黑盒子(这里只是理解上这么做,跟开源没关系),你的程序在需要调用系统服务的时候包含总头文件OK了。
但是一个工程中,除了uCOS/II本身的文件,我们自己编写的应用模块可能还有好多个,它也不是简单的像:
aa.h   aa.c
bb.h   bb.c
...
然后在main.c中包含aa.h,  bb.h  等头文件一样,在aa.c中你肯俄国调用了bb.c中的内容。

因此感觉10楼所说的头文件树是比较合适的,希望HWM能给出一个例子来讨论讨论。

--------------

 keil 中自己编写C语言头文件 
 
自己编写一个C语言头文件,把自己常用的一些函数放进去。所看到文章做法和一般C语言头文件写法基本一样,自己学着试了一下,老是不成功。后来去图书馆查书,才知道原
来keil 的C语言比较特别,引用同一工程其他文件中的函数需要在声明函数前加extern。
 
以下是一个例子:
//步骤一:建立fc.h
#ifndef FC_H
#define FC_H
#include
extern void f(void)
#endif
//步骤二:建立fc.c
#include "fc.h"
#include
//还需要什么头文件自己添加
void f(void)
{
 //要什么程序自己添加
}
步骤三:将f.h和f.c放在工程的文件夹里,并在keil 中将f.c添加到工程中(右键左边的Source Group n,
选择Add file to group 'Source group n'),要用到f()函数的话就include“fC.h”就行了,例如:
#include
#include "fc.h"
void main()
{
f();
while(1);
}
 
结果大功告成,成功编译,但是并没有想象中那么实用,例如 fc.c 中如果定义了函数但没有被引用的话,
keil 会发出警告,虽然可以编译,但是一大堆警告很烦人,也和容易让人忽视其他很重要警告。我想自己
编写头文件主要是适用于大型工程吧。很多人编写各自不同的函数,然后通过头文件的引用把函数给主程
序或者其他子程序引用。
 
注:fc.h也可以放在keil/C51/INC下,引用时变为#include

 

********************************

 

模块化简单说就是将完成某一功能或某一计算处理的程序段单独做成一个函数,输入处理的数据,输出处理后的量。

 

各功能模块单独编写程序,最后通过调用

 

 

每个模块定义一个函数,然后在后面的程序中直接调用就可以了!~

我在网上找个程序给你看看哈!~你看看他是怎么调用函数的?

这个程序有问题,我给你看值是告诉你用函数调用来将长程序模块化的方法,希望能帮到你

#include          

#include

 

 

#define uchar unsigned char

#define uint unsigned int

 

sbit pcf8563_scl=P0^5;//时钟频率

sbit pcf8563_sda=P0^4;//串行数据传输脚

 

 

bit busy=0;

 

uchar sg;//时高位

uchar sd;//时低位

 

uchar fg;//分高位

uchar fd;//分低位

 

uchar mg;//秒高位

uchar md;//秒低位

 

uchar hou=0;

uchar min=0;

uchar sec=0;

 

uchar subadd;//地址

uchar dat;//数据

 

uchar number;

 

void start_pcf8563();//开始数据

void send_pcf8563_byte();//发送

 

void stop_pcf8563();//结束数据

void receive_pcf8563_byte();//接收

void spit_time();//分别计算时、分、秒的各位数字

 

 

void spit_time()//分别计算时、分、秒的各位数字

{

 sg=(int)hou/10;

 sd=(int)hou%10;

 

 fg=(int)min/10;

 fd=(int)min%10;

 

 mg=(int)sec/10;

 md=(int)sec%10;

}

 

 

void Send_pcf8563_byte(uchar bb) //PCF8563发送一个字节

{

  uchar aa;

    pcf8563_scl=0;

 for(aa=0;aa<8;aa++)

 { 

    if((bb&0x80)==0x80)

      {

        pcf8563_sda=1;

      }

    else

      {

        pcf8563_sda=0;

      }

 

      pcf8563_scl=1;

      pcf8563_scl=0;

     bb=bb<<1;

 }

    _nop_();

    _nop_();

 pcf8563_sda=1;

 

 pcf8563_scl=1;

 

    busy=0;

 if(pcf8563_sda)

 {

 busy=1;

 }

    else

 {

    _nop_();

    _nop_();

 pcf8563_scl=0;

    busy=0;

 }

}

 

void write_pcf8563(uchar subadd,uchar dat)// PCF8563对应地址写数据

{

 start_pcf8563();

 Send_pcf8563_byte(0xa2);

 if(!busy)

 {

   Send_pcf8563_byte(subadd);

   if(!busy)

 {

   Send_pcf8563_byte(dat); 

 

 }

  }

  stop_pcf8563();

}

 

void read_pcf8563()          //读当时的时,分,钞

{

 start_pcf8563();

 Send_pcf8563_byte(0xa2);

 

if(!busy)

{

  Send_pcf8563_byte(0x02);

  if(!busy)

  {

  start_pcf8563();

  Send_pcf8563_byte(0xa3);

  receive_pcf8563_byte();

  sec=number&0x7f;

 

 

  start_pcf8563();

  Send_pcf8563_byte(0xa3);

  receive_pcf8563_byte();

  min=number&0x7f;

 

 

  start_pcf8563();

  Send_pcf8563_byte(0xa3);

  receive_pcf8563_byte();

  hou=number&0x3f;

 

 }

}

stop_pcf8563();

}

 

void receive_pcf8563_byte()   //PCF8563接受一个字节

{uchar cc;

pcf8563_sda=1;

 number=0;

 for(cc=0;cc<8;cc++)

  {

  number<<=1;

  pcf8563_scl=0;

 

  pcf8563_scl=1;

  _nop_();

  _nop_();

  number= number|pcf8563_sda;

 }

  pcf8563_scl=0;

 _nop_();

 _nop_();

 

}

 

 

 

void start_pcf8563() //开启PCF8563IIC

{

pcf8563_sda=1;

pcf8563_scl=1;

pcf8563_sda=0;//SCL为高,SDA执行一个下跳

 

pcf8563_scl=0;//SCL为低,嵌住数据线

}

 

void stop_pcf8563()   //关闭PCF8563IIC

{

pcf8563_sda=0;

pcf8563_scl=1;

pcf8563_sda=1;//SCL为高,SDA执行一个上跳

 

pcf8563_scl=0;//SCL为低,嵌住数据线

}

 

 

void main(void)

{

 

write_pcf8563(0x02,sec);   //写钞

write_pcf8563(0x03,min);   //写分

write_pcf8563(0x04,hou);   //写时

 

 

while(1)

{

    read_pcf8563();//读当前时间

 spit_time();   //切换时间,为显示做准备

 

}

}