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

原帖:https://blog.csdn.net/trap94/article/details/50602090
通常先写一个.c文件,然后把把函数主体写在.c文件内,然后在.h文件中声明,再include .h。为何不直接写在.h文件里面,然后之间include .h

原因如下:
1.因为会产生重复定义的问题!
2…从软件工程的角度,代码的实现不会写在头文件里面。因为它违背了隐蔽细节的原则,也就是我们需要暴露的是接口而不是细节。你不需要告述别人的代码是如何实现的,你只要提供接口就行啦。头文件就是c语言的接口。因为你想调用别人的接口只需要include别人的头文件,再连接或动态的调用别人的库就行啦。
3…从编译的角度,你如果写在头文件里面,改一次代码,和这个头文件有关嗯文件都要重新编译,这对大型项目来说非常耗时的。
4.亲测对于小型工程这样是可行,但是还是要养成主体函数写在 .c 里,然后在 .h 里面声明,接着在再include .h

但我们还知道,我们还有#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都是可以的,因为只有重复定义会报错,重复声明是不会报错的。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值