2.c的多文件编译技巧---“.h”文件的多重包含防出错

    通常一个C程序工程按功能可以分成多个模块, 一个模块通常由两个文档组成一个头文件 *.h, 对模块中的数据结构和函数原型进行描述;另一个为C文件*.C , 对数据实例或对象进行定义,以及函数算法的具体实现,如I2C.C, SPI.C, DAC.C, DISPLAY.C 等,为了文件的调用,我们要为每个模块定义一个头文件,以I2C.C 来说,定义I2C.H。

#ifndef GRAPHICS_H                    /*防止graphics.h被重复引用*/
     #define GRAPHICS_H                
                                       
#include   <math.h >                    /*引用标准库的头文件*/
…                                       
#include   “myheader.h”               /* 引用非标准库的头文件*/
…                                          
void   Function1(…);                      /*全局函数声明*/
…                                       
class   Box                                    /*类结构声明*/
{

};


#endif
 
    模块化的程序是黑盒,只向外提供接口(全局变量、外部函数),而不需要让调用者了解其中过程。尽可能地少定义接口有利于保持模块的独立性(不需要让使用者知道的内部函数与静态全局变量不需要在H文件中给出以避免使用者疑惑)在需要调用此模块的文件中写入include语句。一个好的工程,H文件的组织是很清晰的,只看H文件就能够写主程序调用相应的C模块。

       头文件的格式如下(I2C.H为例):
********************************************************************

 #ifndef   I2C_H                        /*是否没有定义过 "I2C_H”, 防止重定义*/
     #define   I2C_H                    /*定义"I2C_H" */
 
     ..........
     bit  SetSDA ( bit  Up_Down );

     bit   SetSCL ( bit  Up_Down);

#endif       

**********************************************************************
 
           I2C.C格式如下:
 
**********************************************************************
#include  < stdio.h >
#include  "I2C.h"
 
void SendByte ( uchar c );                        /*内部函数在.H 头文件中不描述*/

bit  SetSDA ( bit  Up_Down )     { .......... };
 
bit   SetSCL ( bit  Up_Down)     { .......... };
**********************************************************************
另外一种写法:

=============================
 
 #ifndef   I2C_H
 
     #define   I2C_H
    
     ..........
     exten  bit  SetSDA ( bit  Up_Down );
     exten  bit   SetSCL ( bit  Up_Down);
 
#endif  
 
=================================================
 I2C.C格式如下:
 
=================================================

#include  < stdio.h >


void SendByte ( uchar c );                           /*内部函数在.H 头文件中不声明*/

bit  SetSDA ( bit  Up_Down )     { .......... };

bit  SetSCL ( bit  Up_Down)      { .......... };
 
=================================================

 

 

 

举个例子,顺便分析一下ifndef/define/endif:
假设你的工程里面有4个文件,分别是a.cpp, b.h, c.h, d.h。
a.cpp的头部是:
     #include   "b.h"
     #include   "c.h"

b.h和c.h的头部都是:
     #include   "d.h"

    而d.h里面有class D的定义。
    这样一来, 编译器编译a.cpp的时候,先根据#include "b.h"去编译b.h这个问题,再根据b.h里面的#include "d.h",去编译d.h的这个文件,这样就把d.h里面的class D编译了;
    然后再根据a.cpp的第二句#include "c.h",去编译c.h,最终还是会找到的d.h里面的class D,但是class D之前已经编译过了,所以就会报重定义错误。

    加上ifndef/define/endif,就可以防止这种重定义错误。在预编译的过程中,执行到include "C.h"时会因为在上一句的时候已经定义了class D这个宏,所以此时的ifndef条件不满足,起到了防止重复引用头文件的效果。
 
     #undef只是撤消掉掉原来定义的宏,但是不会取消掉你已经用这个宏定义的变量
     #define   X   extern
     x   int   a;
     #undef   X

     你仍然可以使用这个a,但不能用X了,当然你再定义X成什么就随便了
你也可以再定义成
     #define   X   extern
               x   int   a;
     #undef    X
     #define   X   int
               X   b;
     #undef    X

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值