标题: 用#ifndef #define #endif写头文件的一点总结 [打印本页]

作者: aabbcc    时间: 2014-12-6 17:55
标题: 用#ifndef #define #endif写头文件的一点总结


      以前写程序时,头文件里都用了#ifndef xxx  #define xxx ......  #endif,因为知道这是一种条件编译,防止重复,在多个.c文件里都可以#include "xxx.h"了,也就这么用了,但是这两天编写一个小程序时,照这么写编译连接时却提示重复定义,于是就不知道了,明明已经用条件编译防止重复了呀。于是在网络上各种找答案,最后发现了问题所在,再加上自己的一些理解,在这里做个总结,以防以后又忘了。

      #ifndef xxx  #define xxx ......  #endif这个应该是防止重复声明而不是防止重复定义(可能这么说也不准确)。应该keil编译器是这样的,允许多次声明,只要每次声明不发生冲突(所谓冲突,举个例子,比如在一个文件里声明的函数为void a(void);,而在另一个文件里声明的却是void a(int a);,这就是函数原型冲突了。),程序就是能正常编译连接的,因为声明只是告诉编译器一个符号是什么或函数原型是什么,但定义就涉及到存储空间、地址等等这些了。还有就是他是能在同一个编译单元中防止重复(我猜想同一个编译单元就姑且把他认为是同一个.c文件吧,也许不对。),但是在不同的编译单元之间他是不能传递的,只有在最后链接输出可执行文件时再来把编译生成的每个.o或.obj一起链接,在这个过程中可能就会提示重复定义而导致无法链接输出可执行文件了。再来看看我出现的问题,原来我是在头文件里定义变量了,形如:

#ifndef xxx

#define xxx

unsigned char a[]={..........};  

............

#endif

这样,在每个.c文件里单独编译的时候,能正常编译出.o文件,但是在链接时就会发现多个.o文件中包含相同的symbol a,从而导致无法正常链接造成程序不成功。

      解决方法就是对于一般的变量就不要在头文件里定义,如果是想多个.c文件访问(分享)同一个变量,那么可以在头文件里声明为全局的外部变量,当然关键字什么的大家都知道了,我也知道,形如:extern 数据类型 变量名; (不过好像用keil开发51单片机程序时数据类型bit 可以省略不写,有点忘记了。),然后在某一个.c文件中定义一下该变量就可以了。不过记住,extern是声明而不是定义,所以在头文件中千万不要给他初始化,只有在.c文件中定义时才可初始化。如果你是想在头文件里写一个常量大数组给后面的程序用,比如 const unsigned char image[]={......}; ,那你就只能在要用他的那个.c文件里#include "xxxx.h"了,其他地方不能在#include "xxxx.h"了,因为你是在该头文件里定义变量。我的问题就是这种。



作者: 1250455243    时间: 2014-12-7 12:05
好。。
作者: 1250455243    时间: 2014-12-7 12:06
支持。
作者: mycookie    时间: 2014-12-9 10:35
好久没这么细致的研究C了
作者: chweji123    时间: 2014-12-10 14:40
好。。
作者: 腾飞的龙    时间: 2015-11-2 13:07
受益匪浅,谢谢!
作者: sdlwzk    时间: 2015-11-2 22:01
之前一直模模糊糊的,不会用头文件
作者: JY脚印    时间: 2016-2-6 23:43
有所收获!谢谢!!!
作者: wuxishun    时间: 2017-11-26 12:04
对程序看不懂,也不会编,感觉好难




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1