静态组织惯例:
1、尽量用树形结构组织模块,即尽量保证单级调用关系,即上级调用者不要使用下级调用的模块中的函数、变量,不要有跨级调用关系,更不要有循环调用关系,可以有自身的递归调用关系。
2、给每个.c文件建立一个.h文件,在其中声明所定义的全部函数(可以省略extern修饰)和全部内部变量,确保用extern修饰,确保.c文件中有对应的变量定义,确保.c文件的变量定义之前就#include "filename.h"。
3、对于模块中用到了其它模块的变量或者函数,要在.c文件中的变量定义之前追加对应的模块头文件#include "externalfilename.h";同时指示链接器(linker)链接相应模块编译后的.o文件,不然只能通过compiling阶段,在linking阶段报告找不到汇编级函数入口的错误和定义前使用变量的违例。
4、代码整合时,在相应的项目文件中(makefile),用 本模块的.c文件 + 被包含的其它模块的.h文件 (或者只是用全部包含的.h文件)来表达模块依赖关系,用.c文件来表达编译对象。
5、对于确实要在调用树中的多级使用到的模块,根据调用者的分布,尽量归为少数几个模块库(用一个.h+.c文件容纳),便于日后检查调用关系图。对于比较复杂的跨级调用关系,要在被调用的库模块的.h文件中加入#define LIB_THIS_FILENAME_H,同时在调用者的.c文件中使用conditional directive:#ifndef LIB_INVOKEE_FILENAME_H #include "LIB_INVOKEE_FILENAME_H" #endif 这样形式来避免重复包含带来的“re-declaration”错误。
开发过程惯例:
6、设计可以从编写makefile文件开始,勾画出模块框架、模块功能分配表和调用关系图,并且touch 所需要到的.h文件和.c文件。然后在.h文件按照既定功能“列出”(实际是声明)所有变量和函数,并且在.c文件中编写相应的“空壳(nut)”。最后在.c文件头部填写相应的.h文件“列表”,表达调用关系。
7、编写时的第一要点是保证模块的.c文件和.h文件同步更新,修改时先从.h文件开始。也可以从.c文件开始,然后利用工具重新生成.h文件。
8、调试功能原型时,对于一些可能要用到辅助信息的检查,例如多个实现版本的对比,基于ADT的算法调试,一律采用#ifdef DEBUG #endif 限定起来,并且输出设备指向stdout。
8、对于那些即使在最终确认的程序中仍然可能要检查的信息,比如关键数据结构的状态历史,关键的流程转移标记,一律指向stderr输出,在需要时可以查看stderr端口检查。
9、在主函数或者核心函数的文件第一行加入#define DEBUG指示,在项目makefile中或者测试脚本中使用 sed -i "1/s/#define DEBUG/\/\* #define DEBUG \*\//" MAIN_FILENAME.c 生成程序的最终版本。如果stderr输出影响性能,也可以通过sed去除所有的stderr的输出:sed -i "/s/fprintf(stderr\(*\)$/\/\* fprintf(stderr\(1\)/" *.c
阅读(790) | 评论(0) | 转发(0) |