由static引发的关于函数定义顺序与位置的纠结和打算

 

  近几年的编程中,我越来越倾向于以严格的字母顺序来安排函数在源代码中的出现顺序,比如将finalise函数的定义写在init函数定义的前面。其实这样也说不上有什么好处,只能算是一种洁癖。不过这样就会导致我经常遇到这种情况:func1和func2是两个内部函数,func1要调用func2,但是func1的定义却出现在func2的前面。此时我通常会将func2的声明写在func1的定义里,就像下面这样:

 

  但是今天我将一个VC项目从C切换到C++后,发现上面这样的代码无法链接成功!链接器说找不到func2的定义。如果我要保持这两个函数的定义顺序的话,就只能:要么将func2的声明从func1的定义里拿出来,放在func1定义的前面;要么将func2定义前的static修饰符去掉。我在网上搜了很久,都没有找到C++标准关于这个问题的说明。我尝试过在func1中的func2声明前加上static,却得到“static functions with block scope are illegal”的错误消息。

  不知在gcc中是否也会出现同样的现象。可惜我现在正在用公司的电脑,没有gcc可用。回去后在自己的笔记本上做做实验。

  这时我想,也许以后是不是要在源文件的开头就把所有函数都声明一遍,以免出现这样的问题。但是转念一想,这样做实在是太麻烦了,而且好像也没见哪个开源项目的代码是这样做的。为了确认一下,我打开了手头的两个开源项目:libevent和SQLite。

  libevent并没有这样做,只是在某些函数的定义前面声明了少量的内部函数。

  SQLite则这样做了。那长达10万多行的唯一的c文件中,开头1万多行全是各式各样的类型定义、宏定义和函数声明,而且似乎所有的函数都被声明了一遍——包括全局函数。

  那么我是不是应该学学SQLite的风格呢?似乎不是的——因为我读了读那份.c文件——即sqlite3.c的最开头的注释。原来SQLite项目为了使代码尽可能轻便、自包含,将所有头文件的内容全部复制到了这份c文件中。比较有趣的是,内部函数的声明也放在了头文件中。

  另外,这次我特意留意了一下,这两个开源项目的代码都没怎么按照字母顺序来排列函数的定义。尤其是libevent,函数定义的出现顺序似乎并没什么规律。SQLite似乎好一些,功能相近的函数是放在一起的,比如winMutex*这类Windows平台下的锁函数就放在一起。

  我想恐怕也要改改自己那没什么意义的洁癖了。考虑过后,我打算今后这样安排函数的定义顺序:

  1. 不再按照字母顺序放置函数的定义,而是将功能相近的函数放在一起,并且尽量给它们起相同的前缀名。这样做的好处是:在IDE的函数列表中,功能相近的函数都贴在一起,方便查找。
  2. 全局函数的定义顺序应与它们在头文件中的声明顺序相同。但是main函数的定义总是放在文件的末尾,因为这个函数最特殊。
  3. 不要在函数内部声明其它函数,免得出现文章开头提到的问题。
  4. 至于内部函数,那些通常是辅助函数,就把它们放在引用者之前吧,这样便于代码的阅读者找到它们。但是如果某个辅助函数有多个引用者,那就在源文件的开头声明它,在文件的结尾处定义它——因为更重要、更被读者关心的全局函数应该放在前面,就像类公有成员应在私有成员之前定义一样。另外,定义的顺序也应与声明的顺序相同。

  这样在没有IDE和源码阅读工具的情况下,读者就可以这样阅读我的代码:从头文件可以知道全局函数,然后从源文件的开头往下读,查找自己感兴趣的全局函数。如果碰到了感兴趣的辅助函数,可以在调用它的全局函数的前面找,如果找不到就看看文件的开头,通过它的声明知道它的出现顺序,然后再到文件结尾处找它的定义。

  虽然可以用普通文本编辑器的查找功能来查找函数,但是根据我的经验,如果一个函数被调用很多次,那么用普通的查找功能来找到它的定义是一件很麻烦的事。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值