2.c的多文件编译技巧---“.h”文件的多重包含防出错
2009-03-16 23:16
309 查看
通常一个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
#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
相关文章推荐
- 头文件多次包含编译出错
- Java源文件编译出错:类文件包含错误的类 请删除该文件或确保文件位于正确的类路径子目录中
- 在vs2010下,opencv2.2编译出错的:找不到头文件
- c++基础(3.5)预处理:宏、文件包含、条件编译
- C语言学习入门 (六) 预处理指令:宏、条件编译、文件包含
- Solaris编译Boost生成so文件出错:failed gcc.link.dll解决方法
- c++中类模板的声明和定义中把.h与.cpp分离时编译文件包含问题
- 试图运行项目时出错:未能加载文件或程序集 或它的某一个依赖项。该模块应包含一个程序集清单
- c++编译包含头文件问题
- Windows命令行下编译包含中文字符的Java文件报错
- MyEclipse中js文件包含中文时保存出错的解决方法
- C语言学习11:typedef和define区别,头文件的使用以及 <>和“”区别,宏定义中#和##的用法,条件编译,gcc和c99中宏定义使用printf和sprintf,条件编译避免头文件包含
- 文件包含---多个源程序的编译和链接
- ant编译打包可运行的jar文件,并包含所依赖的第三方jar包
- cocos2dx 打包,Android.mk包含编译文件的办法
- ADS1.2编译时出错,提示找不到一个不存在目录下的目标文件(*.o)
- 解决Visual C++工程中包含 .c 或cpp文件编译时产生的.pch预编译头错误(C1853)的办法
- C语言预处理指令:宏、条件编译、文件包含
- 用Gcc编译包含glib.h头文件的源程序
- 建立工程后刚开始编译出现了“error PRJ0003 : 生成 cmd.exe 时出错”这样的错误,虽然在debug中生成了.exe文件,但是无法执行,提示找不到mfc90ud.dll。