我应该如何在C中构build复杂的项目?
我比初学C级的技能要多一点,并想知道是否有任何事实上的“标准”来构造一个在C中有些复杂的应用程序,甚至是基于GUI的应用程序。
我一直在使用Java和PHP中的OO范例,现在我想学习C,恐怕我可能会以错误的方式构build我的应用程序。 我不知道如何使用程序语言来实现模块化,解耦和干燥的准则。
你有任何阅读build议? 我找不到任何C的应用程序框架,即使我不使用框架,我总是通过浏览他们的代码find好主意。
关键是模块化。 这更容易devise,实施,编译和维护。
- 识别您的应用程序中的模块,例如OO应用程序中的类。
- 单独的接口和每个模块的实现,只把接口放在其他模块需要的接口中。 请记住,在C中没有命名空间,所以你必须使你的接口中的所有东西都是唯一的(例如,带有前缀)。
- 在实现中隐藏全局variables,并使用访问器函数进行读取/写入。
- 不要以inheritance的方式思考,而要从构成的angular度来考虑。 一般来说,不要试图在C中模仿C ++,这将是非常难以阅读和维护的。
如果您有时间学习,请参阅Ada应用程序的结构及其必需的package
(模块接口)和package body
(模块实现)。
这是编码。
为了维护(请记住,你编码一次,但你维护几次),我build议logging你的代码; Doxygen对我来说是一个不错的select。 我build议也build立一个强大的回归testing套件,它允许你重构。
OO技术不能在C中应用是一个常见的误解。大多数情况下,它们只是比用语言专用的语言稍微笨拙一些。
强大的系统devise的基础之一是在接口背后封装一个实现。 FILE*
和与它一起工作的函数( fopen()
, fread()
等)是如何在C中应用封装来build立接口的一个很好的例子。 (当然,因为C没有访问说明符,所以你不能强制没有人在struct FILE
偷看,但是只有受虐狂才会这么做)。
如果需要的话,可以在C中使用函数指针的表格进行多态行为。 是的,语法是丑陋的,但效果是一样的虚拟function:
struct IAnimal { int (*eat)(int food); int (*sleep)(int secs); }; /* "Subclass"/"implement" IAnimal, relying on C's guaranteed equivalence * of memory layouts */ struct Cat { struct IAnimal _base; int (*meow)(void); }; int cat_eat(int food) { ... } int cat_sleep(int secs) { ... } int cat_meow(void) { ... } /* "Constructor" */ struct Cat* CreateACat(void) { struct Cat* x = (Cat*) malloc(sizeof (struct Cat)); x->_base.eat = cat_eat; x->_base.sleep = cat_sleep; x->meow = cat_meow; } struct IAnimal* pa = CreateACat(); pa->eat(42); /* Calls cat_eat() */ ((struct Cat*) pa)->meow(); /* "Downcast" */
GNU编码标准已经发展了几十年。 阅读这些信息是一个好主意,即使你没有听从这封信。 思考这些问题提出的观点将为您如何构build自己的代码奠定更坚实的基础。
所有好的答案。
我只会添加“最小化数据结构”。 在C中,这可能更容易一些,因为如果C ++是“C with class”,OOP试图鼓励你把每个名词/动词放在脑海中,并把它变成一个类/方法。 这可能是非常浪费的。
例如,假设您在某个时间点有一组温度读数,并且想要在Windows中将它们显示为折线图。 Windows有一个PAINT消息,并且当你收到它时,你可以循环执行LineTo函数的数组,当你将数据转换为像素坐标时缩放数据。
我所见过的次数太多了,因为图表是由点和线组成的,所以人们会build立一个由点对象和线对象组成的数据结构,每个数据结构都有能力自己绘制,然后使之持久化,理论上说在某种程度上“更高效”,或者他们可能必须能够将鼠标放在图表的某些部分上,并以数字方式显示数据,因此他们将方法构build到对象中来处理这些问题,当然,涉及创build和删除更多的对象。
所以你最终得到了大量的可读性好的代码,而且只花了90%的时间来pipe理对象。
所有这些都是以“良好的编程实践”和“效率”的名义完成的。
至less在C中,简单,有效的方式会更加明显,build造金字塔的诱惑力也会减弱。
如果您知道如何在Java或C ++中构build代码,那么您可以使用C代码遵循相同的原则。 唯一的区别是,你没有编译器在你身边,你需要做的一切手工仔细。
由于没有软件包和类,你需要从精心devise你的模块开始。 最常见的方法是为每个模块创build一个单独的源文件夹。 您需要依靠命名约定来区分不同模块之间的代码。 例如,用模块的名称前缀所有函数。
你不能有C类,但你可以很容易地实现“抽象数据types”。 您为每个抽象数据types创build一个.C和.H文件。 如果你喜欢,你可以有两个头文件,一个公共和一个私人。 这个想法是,需要导出的所有结构,常量和函数都会转到公共头文件。
你的工具也很重要。 C的有用工具是lint ,它可以帮助你在你的代码中find不好的气味。 另一个可以使用的工具是Doxygen,它可以帮助您生成文档 。
复杂应用的数字规则:应该很容易阅读。
为了使复杂的应用程序更简单,我使用Divide和征服 。
无论开发语言如何,封装对于成功的开发都是至关重要的。
我用来帮助封装C中“私有”方法的一个技巧就是不要在“.h”文件中包含它们的原型。
我build议阅读一个C / C ++的教科书作为第一步。 例如,C Primer Plus是一个很好的参考。 通过这些例子来看看如何将你的Java OO映射到更像C这样的过程语言。
我build议你查看任何stream行的开源C项目的代码,例如…嗯… Linux内核或Git; 看看他们是如何组织的