免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 18113 | 回复: 4
打印 上一主题 下一主题

关于头文件中的函数定义 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-09 16:19 |只看该作者 |倒序浏览
有几个疑问:

1.在头文件中定义inline函数是可以的,可为什么不能在头文件中定义普通的函数呢?不是说inline仅仅是
对编译器的建议吗?如果被编译器忽略了呢,那不跟普通函数一样了吗?

2.在头文件声明函数,cpp文件中定义函数很好理解,在头文件中定义类也很好理解。至于在头文件中定义
函数,为什么会有这种需求呢?我代码写得少,读的少,想不清楚。

3.这些问题的答案,也就是说这样的用法到底合不合法,肯定基于一个准则吧,这个准则是什么呢?哪本书
或资料里有介绍呢?希望从根本上得到个解释~

论坛徽章:
0
2 [报告]
发表于 2009-11-09 17:55 |只看该作者
1.你想在头文件中定义普通函数也可以,没人拦着你
至于inline函数,因为在编译的过程中就要进行“替换”,所以你必须要定义在头文件中并且也要include,不然编译器怎么知道这个inline函数是啥?当然你直接把这个inline函数实现的.c给include了也可以。至于普通的函数,是在链接过程中resolve的,所以不存在这个问题,在头文件中只需要有declaration就可以了。没有declaration的话c也是可以,但是很危险,因为这样的话编译器就不能帮你做函数类型检查了(比如说形参个数,返回类型),而且对于没有声明过的函数,gcc会帮你implicit推断出一个返回值为int的函数,这在有些情况下是相当危险的。这部分你可以去看看函数的argument passing以及调用的过程。
一句话,你需要理解编译和链接这两个过程都干了点什么?
比较好的著作你去看看hacking helloworld,一个台湾人写的文章

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
3 [报告]
发表于 2009-11-09 18:05 |只看该作者
先回答这个问题吧:
3.这些问题的答案,也就是说这样的用法到底合不合法,肯定基于一个准则吧,这个准则是什么呢?哪本书
或资料里有介绍呢?希望从根本上得到个解释~


首先要知道如下两点:

1、扩展名不提供任何功能。

所以,技术上根本不需要区分何谓头文件、何谓实现文件。

所谓include,其实就是指示编译器,让它把指定文件的内容拷贝过来,把 #include 那一行给覆盖了。

所以,可以认为,最终给编译器看到的东西里面,include是不存在的,只有单纯的函数原型声明,可能还有部分或者全部这些函数的实现。

这样一份已经被整合过的文件,就叫做一个编译单元。它最终对应一个.o文件(windows下是.obj)。


下一步就可以用链接器把所有这些编译单元、静态库以及动态库统统链接起来,形成可执行文件或者库。



2、如上,想象一下,如果一个很大的项目,没有规矩,谁想包含谁都可以,这样东拉西扯下来会出现什么?

显然,首先是程序不敢改了。一改别人的文件也跟着变,这哪受得了。

其次,程序很难编译成功。因为这个.o文件里有函数A的实现,那个.o文件里也有函数A的实现,链接器哭了:我究竟该以谁为准啊。
最糟糕的时候,还可能出现循环依赖,甚至是包含关系死循环。

所以,程序界哪些聪明的先行者们就约定,大家都把文件分两种,一种叫头文件,只声明接口,不准写实现代码,这样只要接口名字不冲突头文件就可以随便包含;另一种叫实现文件,实现文件里就随便搞了;但必须注意,任何人都不准包含实现文件——否则链接器就又要哭了。




了解了以上基础,你的这些问题就很好回答了:

1.在头文件中定义inline函数是可以的,可为什么不能在头文件中定义普通的函数呢?不是说inline仅仅是
对编译器的建议吗?如果被编译器忽略了呢,那不跟普通函数一样了吗?


inline的含义本身,就是“让编译器把删掉了call/return过程的实现代码弄得到处都是”,但如果编译器无法inline,那么它就还原成函数调用。

比如,一个虚函数能不能inline?为什么?



2.在头文件声明函数,cpp文件中定义函数很好理解,在头文件中定义类也很好理解。至于在头文件中定义
函数,为什么会有这种需求呢?我代码写得少,读的少,想不清楚。


没有在头文件里定义函数的需求。原因如上所述。

注意一个特殊情况: STL相当于一种智能宏,它会根据参数自动生成代码。
但没有模板参数怎么办?

所以,STL实现不能当作独立的编译单元,它必须被其他.c文件包含、并提供模板参数之后、才有可能得到真正的实现代码。

所以,严格的说,STL的实现其实也是一种声明。这里面的技术细节更多,不过我们这些不写通用库的人就不需要追究了。

[ 本帖最后由 shan_ghost 于 2009-11-9 18:06 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2009-11-09 20:18 |只看该作者
恩,讲解的比较详细,谢谢两位~

论坛徽章:
0
5 [报告]
发表于 2009-11-10 11:15 |只看该作者
3楼 是老师吧 回答的思路井井有条 让人看了很容易接受.
论坛能有您在 菜鸟们真有福气啊.:wink:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP