eyue 发表于 2006-2-24 23:01:27

一个工程里如何包含多个.c文件和多个.h文件,然后让它能顺利编译通过

大虾,请教了,一个工程里如何包含多个.c文件和多个.h文件,然后让它能顺利编译通过,前段时间在网上下载了高手写的代码,他们在一个文件里包含了n个.c文件,结构太好了,俺也想学习学习,请高手指点,我试过几次,都提示错误

supersai 发表于 2006-2-25 00:26:48

这篇文章里有详细的说明,在第三章!

http://www.ouravr.com/bbs/bbs_upload3433344123780210/files_1/armok0124722.pdf
-----此内容被supersai于2006-02-25,01:18:12编辑过

sonic 发表于 2006-2-25 00:29:27

我也看到过类似这样的例子,不过是汇编的。不过,不同的是,我看过的那个工程只有一个.HEX文件,却有几个程序模块来的,其中有一个.ASM文件,还有几个.INC的文件,不知道是怎么将它们连接起来的?

sonic 发表于 2006-2-25 00:33:51

一楼说的这个地方,为何我打不开?可以复制,却不可以张贴!郁闷!

kinsey 发表于 2006-2-25 09:06:19

一楼那个链接是可以打开的,楼上的是不是你的电脑软件问题呀?

Louis_Bright 发表于 2006-2-25 09:52:00

俺手头这个项目是42个C文件,50个h文件,呵呵,全部是俺一个人写的。

    要想多个文件链接好,首先你自己的文件组织结构要好,至少便于你自己搜索东西,文件命名也要有一定的规律。

    一个C文件一定对应一个H文件,H文件主要作用是一个窗口作用,告诉别人你可以用我的哪些东西,别的文件想调用,包含它的H文件就可以了,然后你一股脑把那些C文件添加进去就OK了。注意extern和static这两个关键字。

    大家不妨看看我随便从我项目中抓出的一个H文件:



DrvTimer0.h:





#ifndef _DRVTIMER0_H_

#define _DRVTIMER0_H_



#ifdef_DRVTIMER0_C_

#define EXTERN

#else

#define EXTERNextern

#endif



#define TIMER0_PRE_FREQ0    0                                 // T/C Stop

#define TIMER0_PRE_FREQ1    BIT(CS00)                           // CLK / 1

#define TIMER0_PRE_FREQ2    BIT(CS01)                           // CLK / 8

#define TIMER0_PRE_FREQ3    (BIT(CS01) | BIT(CS00))             // CLK / 32

#define TIMER0_PRE_FREQ4    BIT(CS02)                           // CLK / 64

#define TIMER0_PRE_FREQ5    (BIT(CS02) | BIT(CS00))             // CLK / 128

#define TIMER0_PRE_FREQ6    (BIT(CS02) | BIT(CS01))             // CLK / 256

#define TIMER0_PRE_FREQ7    (BIT(CS02) | BIT(CS01) | BIT(CS00)) // CLK / 1024

#define TIMER0_PRE_CLK0   0

#define TIMER0_PRE_CLK1   1

#define TIMER0_PRE_CLK2   8

#define TIMER0_PRE_CLK3   32

#define TIMER0_PRE_CLK4   64

#define TIMER0_PRE_CLK5   128

#define TIMER0_PRE_CLK6   256

#define TIMER0_PRE_CLK7   1024



#if   (FOSC == 1000000)

#define TIMER0_PRE_FREQ   TIMER0_PRE_FREQ5

#define TIMER0_PRE_CLK      TIMER0_PRE_CLK5

#elif   (FOSC == 8000000)

#define TIMER0_PRE_FREQ   TIMER0_PRE_FREQ7

#define TIMER0_PRE_CLK      TIMER0_PRE_CLK7

#endif



#if0

#define TIMER0_FREQ         (double)((double)FOSC / TIMER0_PRE_CLK)

#define TIMER0_CNT          (double)(1 / TIMER0_FREQ)

#define TIMER0_COUNT(ms)    (double)(((double)ms / 1000)/ TIMER0_CNT)

#define SET_TIMEO_TCNT(ms)(BYTE)(256 - (TIMER0_COUNT(ms) + 0.5))

#else

#define SET_TIMEO_TCNT(ms)(BYTE)(256 - (BYTE)(((double)ms * FOSC) / (TIMER0_PRE_CLK * 1000) + 0.5))

#endif



#define PAR_SYS_CLK         0

#define PAR_PAN_CLK         1

#define PAR_TIL_CLK         2

#define PAR_CAM_CLK         3

#define PAR_KEY_CLK         4

#define PAR_MAX_CLK         5



#define APP_STAT_CLK      0

#define APP_CAM_CLK         1

#define APP_CAM_SRV_CLK   2

#define APP_MAX_CLK         3



EXTERN void vSetTimer0(BYTE bVal);

EXTERN void vStartTimer0(BYTE bTimerPreFreq);

EXTERN void vStopTimer0(void);

EXTERN void vSetParClk(BYTE bClkId, BYTE bClk);

EXTERN BYTE bGetParClk(BYTE bClkId);

EXTERN void vSetAppClk(BYTE bClkId, WORD wClk);

EXTERN BOOL fgGetAppClk(WORD *pwClk, BYTE bClkId);

EXTERN BOOL fgTimer0Wizard(void);

EXTERN void vInitTimer0(void);



#undefEXTERN

#endif



关于系统架构,大家可以参考我另外一个小松工程下的回帖。

kinsey 发表于 2006-2-25 11:30:58

楼上的是强人,不知能否把你的架构打包传上论坛,估计很多人都想学习一下你的编程习惯(包括我在内)!

Louis_Bright 发表于 2006-2-25 12:59:05

To 楼上:

    承蒙夸奖!

    其实你仔细看我这个H文件就可以得到很多你想知道的东西:



1>

#ifndef _DRVTIMER0_H_

#define _DRVTIMER0_H_

......

#endif



2>

#ifdef_DRVTIMER0_C_

#define EXTERN

#else

#define EXTERNextern

#endif

......

#undefEXTERN



3>

#define TIMER0_PRE_FREQ

#define TIMER0_PRE_CLK



4>

BOOL/BYTE/WORD



5>函数命名



你先分析一下我以上提到的几个问题,我稍后解释。

Louis_Bright 发表于 2006-2-25 13:10:30

1>

这样写是为了避免重复包含H文件,也就是说,同一个C文件包含同一个H文件不止一次,不会出现问题,因为包含第一次后_DRVTIMER0_H_已经有了定义,以后包含的话,里面的东西就再也没有效了。



2>

这个是一个经典用法。

我相信大部分用比较好的编辑器(我用SourceInsight)的人都会有过这样的烦恼:同一个标识(比如变量,或者函数什么的,尤其是变量),你点击它先预览它的原型/定义,结果一下子跳出来好多个,现在好了,你写一个就OK了。

比如上面的函数,如果这个H文件是被对应的C文件——也就是DrvTimer0.c包含,那么EXTERN其实就是一个空的,那么编译器就知道,

EXTERN void vInitTimer0(void);

这个是本文件的函数说明,如果是别的文件包含,那么EXTERN就是extern,那么就知道是别的文件定义的了

想想看,假如在这里定义了一个变量,会发生什么情况呢(这里没有定义变量,比较遗憾)?比如:

EXTERN BYTE _bT0Counter;

如果被DrvTimer0.c包含则是一个变量定义,但如果是另外的函数包含,则变成了一个外部变量声明!!在项目中你点击这个变量,则只会出现一个变量定义,多爽!而且书写起来也方便,修改也方便。大家想想以前是不是该一个变量定义要改很多地方?

#undefEXTERN

这个也很重要,在文件末记得把这个定义清除。

Louis_Bright 发表于 2006-2-25 13:14:34

3>

事实上这些定义是我直接拿了datasheet先写的,也许程序中我只要用到一个,但我都写了,然后在根据实际情况挑我要的。

这样的好处是,以后看程序很直观知道是设置多少,修改更加方便。



4>

为了移植方便,定义了BOOL,BYTE,WORD类型,

事实上也许在另外的MCU上,int之类的定义未必和当前的单片机一样



5>

在嵌入式系统中,匈牙利命名法我觉得很是很合适的。注意函数命名我也是使用的匈牙利命名法

Louis_Bright 发表于 2006-2-25 13:17:30

6>

这一点我开始没有提,就看你能不能看出来了

在我项目中,我是把Timer0作为整个系统不是非常精确的时钟的。

看到那几个MAX没有?

如果我在程序的扩展修改时,需要多几个“计数器”,我只要定义增加的计数器的名字,然后加大MAX就可以了,C文件?不用修改任何代码!

Louis_Bright 发表于 2006-2-25 13:23:28

7>

#if0

#define TIMER0_FREQ         (double)((double)FOSC / TIMER0_PRE_CLK)

#define TIMER0_CNT          (double)(1 / TIMER0_FREQ)

#define TIMER0_COUNT(ms)    (double)(((double)ms / 1000)/ TIMER0_CNT)

#define SET_TIMEO_TCNT(ms)(BYTE)(256 - (TIMER0_COUNT(ms) + 0.5))

#else

#define SET_TIMEO_TCNT(ms)(BYTE)(256 - (BYTE)(((double)ms * FOSC) / (TIMER0_PRE_CLK * 1000) + 0.5))

#endif



这一个也很隐蔽

首先 #if 0 下是设置定时器定时多少ms的推导,但最终用的是另外一个合在一起的那个定义,原因是如果不这样做,由于我们计算机会有甩掉小数点后数据的习惯可能会引起偏差



还有最后加0.5,也是为了四舍五入。

kinsey 发表于 2006-2-25 22:34:13

楼上的辛苦啦!

强烈向你学习!

谢谢你给出详细的解释!

sonic 发表于 2006-2-25 22:43:15

后来我打开了,原因就是没有把五笔转换成英文的~

唉......!

sonic 发表于 2006-2-25 22:48:49

原来里面是个GCC的教程,我现在学的是汇编啊(当初在学校时没有把C语言学好)

请教:在汇编里,如何向C语言一样,可以分几个文件?

wsmcjm 发表于 2006-2-25 23:43:33

COOL文推荐。

zh1112ou 发表于 2006-2-26 20:27:25

精神可嘉! 来自地狱的天使 如真是天时也!!!

twd3621576 发表于 2009-12-30 22:06:04

1楼那本什么书呀 ?

怎么下载不了

xingcai 发表于 2009-12-30 22:36:55

不错

jchqxl 发表于 2009-12-30 22:43:25

学习了,谢谢。

chengtina 发表于 2009-12-31 11:09:38

mark

kangkang 发表于 2009-12-31 13:43:11

mark

vipcff 发表于 2009-12-31 13:52:18

mark

vincent.r 发表于 2009-12-31 14:10:24

1楼的pdf下载不了。

7楼太棒了。

462245281 发表于 2010-8-24 11:31:27

下载不了

xjmlfm1 发表于 2010-8-24 12:55:37

mark

sagetom 发表于 2011-4-11 15:22:40

2楼的PDF不能下载哦!
幽游梦蝶
超赞!

guanmingliang 发表于 2013-3-5 08:57:22

#ifdef_DRVTIMER0_C_

#define EXTERN

#else

#define EXTERNextern

#endif
这个好像写错了,
#ifndef_DRVTIMER0_C_

#define EXTERNextern

#else

#define EXTERN

#endif
指教

zzjjhh250 发表于 2013-3-5 09:25:53

Louis_Bright 发表于 2006-2-25 13:10 static/image/common/back.gif
1>

这样写是为了避免重复包含H文件,也就是说,同一个C文件包含同一个H文件不止一次,不会出现问题,因为包 ...

那么在头文件对应的C文件中就要加上
#define _DRVTIMER0_C_1

wkman 发表于 2013-3-5 09:41:38

偷懒的办法:找一个正常的程序,开始改。。。。{:titter:}

例如下面这个:

http://www.amobbs.com/forum.php?mod=viewthread&tid=1963156&highlight=%E6%B0%B4%E8%B5%84%E6%BA%90

hongmeng 发表于 2014-5-14 23:28:28

感谢楼上高手的讲解,现在还不知道是怎么回事呢?{:sad:}慢慢学了

ijlc1314 发表于 2014-5-15 07:25:21

这帖子,被挖了几次坟
页: [1]
查看完整版本: 一个工程里如何包含多个.c文件和多个.h文件,然后让它能顺利编译通过