C语言为什么要区分.h和.c?为何不能在头文件里写定义?

原贴:https://blog.csdn.net/trap94/article/details/50602090

我们都知道,在写外部函数的时候,应该在源文件中写具体定义,而在对应的头文件中写申明,最后在执行文件中包含这个头文件就行了。


但到底为什么不能在直接在头文件里写定义呢?


一句话解释下:因为会产生重复定义的问题


但我们还知道,我们还有#ifndenf这个东西,如果要问起来这东西是干啥用的,估计大家都知道这东西是用来防止源文件重复包含相同的头文件的,但我们用了这东西是不是表示就允许在头文件里写定义了呢?


准确的说:依然不可以,因为#ifndenf只解决了部分环节的重复定义问题


########给新人科普##########

头文件中#ifndef的用法如下:

#ifndenf __XXXXX_H

#define __XXXXX_H

函数声明

#endif

其中ifndef(if not define)用来判断这个宏有没有定义过,如果没有定义过,说明这个头文件是第一次引用,那么就继续往下执行;如果这个宏定义过了,说明这个头文件已经被包含过了,直接跳到endif,也就是什么都不执行,就可以防止重复包含头文件了。

########################


那么为什么说#ifndef不能解决所有重复定义的问题呢?因为重复定义这个可能发生编译的不同环节,下面我们一个环节一个环节来分析。


第一个环节:预处理


这个环节做两件事,一把include的头文件内容进行替换,二是处理宏定义。不过这个环节并没有对语法进行检查,所以无论怎么重复定义,这个环节都不会报错的,只不过这个环节以后就没有include了,头文件的内容都替换上去了。



第二个环节:编译(汇编+编译)


这个环节是将源文件变成二进制的目标文件,也就是把.c变成.o(windows下是.obj),并且这个环节是会进行语法检查的,所以如果在某个头文件中定义了一个函数,然后源文件中又连续多次包含这个头文件的话,那么在编译阶段就会报错,例子如下所示:




因此我们需要利用#ifndef来避免重复包含相同的头文件(表面上看好像不会有人傻到像我上面这样连着写很多一样的include,但是我们知道头文件是可以嵌套包含的,如果a.h中包含着b.h,而如果你的.c文件又同时包含了a.h和b.h,一旦项目复杂了,这种情况是否就有可能发生了呢)所以使用#ifndef还是很有必要的。


ok,到目前为止,#ifndef成功地帮我们解决了在编译阶段的重复定义问题,不过它能做的也仅限于此了。


第三个阶段:链接


这是我之前一直都没有想通的一个地方,先看下面这个例子:





上面这个例子的头文件中使用了ifndef,但是最后还是出现了重复定义的问题,为什么呢?原因是在编译阶段,每个源文件都是独立编译的,他们会生成独立的.o文件,这些文件单独出来看的话是每个问题的,每个源文件都只有一次定义,因而编译通过,生成了main.o和file.o这两个目标文件,但这两个文件中各有一次定义,所以在链接阶段,把这个两个目标文件链接在一起的时候就变成有两次定义了,也就出现重复定义的问题了。


总结一下,ifndef可以解决编译阶段发生的重复定义问题,但不能解决链接阶段发生的重复定义问题,所以不要在头文件中作具体定义!


当然以上所说都是在头文件中进行了定义的情况,如果没有在头文件中作定义,而只是声明的话,那么,要是不讲就的话,哪怕不写ifndef都是可以的,因为只有重复定义会报错,重复声明是不会报错的。

猜你喜欢

转载自blog.csdn.net/a445849497/article/details/80512814
今日推荐