C 语言对模块化支持的欠缺
创始人
2024-07-29 02:11:41
0次

模块化是最高原则之一(在 《Unix 编程艺术》一书中, Unix 哲学第一条即:模块原则),我们就当考虑如何简洁明快的使用 C 语言实现模块化。

除开 C/C++ ,在其它现在流行的开发语言中,缺少标准化的模块管理机制是很难想象的。但这也是 C 语言本身的设计哲学决定的:把尽可能多的可能性留给程序员。根据实际的系统,实际的需要去定制自己需要的东西。

对于巨型的系统(比如 Windows 这样的操作系统),一般会考虑使用一种二进制级的模块化方案。由模块自己提供元信息,或是使用统一的管理方案(比如注册表)。稍小一点的系统(我们通常开发接触到的),则会考虑轻量一些的源码级方案。

首先要考虑的往往是模块的依赖关系和初始化过程。

依赖关系可以放由链接器或加载器来解决。尤其在使用 C 语言时,简单的静态库或动态库,都不太会引起大的麻烦。

C++ 则不然,C++ 的某些特性(比如模板类静态成员的构造)必须对早期只供 C 语言使用的链接器做一些增强。即使是精心编写的 C++ 库,也有可能出现一些意外的 bug 。这些 bug 往往需要对编译,链接,加载过程很深刻的理解,才能查出来。注:我并不想以此来反对使用 C++ 做开发。

我们需要着重管理的,是模块的初始化过程。

对于打包在一起的一个库(例如 glibc ,或是 msvcrt ),会在加载时有初始化入口,以及卸载时有结束代码。我想说的不是这个,而是我们自己内部拆分的更小的模块的相互依赖关系。

谁先初始化,谁后初始化,这是一个问题。

在 C++ 的语言级解决方案中,使用的是单件模块。要么由链接器决定以怎样的次序来生成初始化代码,这,通常会因为依赖关系和实际构造次序不同而导致 bug (注:我在某几本 C++ 书中都见过,待核实。自己好久不写 C++ 也没有实际的错误例子);要么使用惰性初始化方案。这个惰性初始化也不是万能的,并且有些额外的开销。(多线程环境中尤其需要注意)

我使用 C 语言做初期设计的时候,采用的是一种足够简单的方法。就是,以编码规范来规定,每个模块必须存在一个初始化函数,有规范的名字。比如 foo 模块的初始化入口叫

  1. int foo_init() 

规定:凡使用特定模块,必须调用模块初始化函数。

为了避免模块重复初始化,初始化函数并不直接调用,而是间接的。类似这样:

  1. mod_using(foo_init); 

mod_using 负责调用初始化函数,并保证不重复调用,也可以检查循环依赖。

在这里,我们还约定了初始化成功于否的返回值。(在我们的系统中,返回 0 表示正确,1 表示失败)然后定义了一个宏来做这个使用。

  1. #define USING(m) if (mod_using(m##_init,#m)) { return 1; } 

注:我个人反对滥用宏。也尽可能的避免它。这里使用宏,经过了慎重的考虑。我希望可以有一个代码扫描器去判断我是否漏掉了模块初始化(可能我使用了一个模块,但忘记初始化它)。宏可以帮助代码扫描分析器更容易实现。而且,使用宏更像是对语言做的轻微且必要的扩展。

这样,我的系统中模块模块的实现代码最后,都有一个 init 函数,里面只是简单的调用了 USING 来引用别的模块。例如:

  1. #include "module.h"  
  2. /*  
  3. 我个人偏爱把 module.h 的引入放在源文件最后,初始化入口之前。  
  4. 它里面之定义了 USING 宏,以及相关管理函数。  
  5. 这样做是为了避免在代码的其它地方去引入别的模块。  
  6. */ 
  7. int 
  8. foo_init()  
  9. {  
  10. USING(memory); // 引用内存管理模块  
  11. USING(log); // 引用 log 模块  
  12. return 0;  
  13. } 

至于模块的卸载,大部分需求下是不需要的。今天在这里就不论证这一点了。

原文链接:http://blog.codingnow.com/2010/01/c_modularization.html

【编辑推荐】

  1. CSS模块化编码 让开发事半功倍
  2. 学习笔记 Flex模块化详尽解读
  3. OSGi,Java模块化框架的另类进化
  4. Python编程语言如何进行模块化修改
  5. 2.3 模块化程序设计

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...