我只有初学者级别的C技能,并且想知道是否有任何事实上的“标准”来构建C中有点复杂的应用程序。甚至是基于GUI的。
我一直在Java和PHP中使用OO范例,现在我想学习C我害怕我可能以错误的方式构建我的应用程序。我不知道要遵循哪些指导方针,使用程序语言实现模块化,脱钩和干燥。
你有任何建议吗?我找不到C的任何应用程序框架,即使我不使用框架,我总是通过浏览他们的代码找到好的想法。
答案 0 :(得分:48)
关键是模块化。这更容易设计,实现,编译和维护。
如果您有时间学习,请查看Ada应用程序的结构,包括强制性package
(模块界面)和package body
(模块实施)。
这是为了编码。
为了维护(记住你编码一次,但你保持了几次)我建议记录你的代码; Doxygen对我来说是一个不错的选择。我还建议建立一个强大的回归测试套件,它允许你重构。
答案 1 :(得分:30)
一种常见的误解是,OO技术不能应用于C.大多数情况下 - 只是它们比具有专用于该工作的语法的语言稍微笨拙。
强大的系统设计的基础之一是在接口后面封装实现。 FILE*
以及使用它的函数(fopen()
,fread()
等)是如何在C中应用封装来建立接口的一个很好的例子。 (当然,由于C缺少访问说明符,你不能强制执行struct FILE
内没有人偷看,但只有受虐狂会这样做。)
如果需要,可以使用函数指针表在C中获得多态行为。是的,语法很难看,但效果与虚函数相同:
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" */
答案 2 :(得分:12)
所有好的答案。
我只会添加“最小化数据结构”。这在C语言中甚至可能更容易,因为如果C ++是“带有类的C”,OOP会试图鼓励你把每个名词/动词放在头脑中并把它变成一个类/方法。这可能非常浪费。
例如,假设您在某个时间点有一系列温度读数,并且您希望在Windows中将它们显示为折线图。 Windows有一条PAINT消息,当你收到它时,你可以遍历执行LineTo功能的数组,在你将数据转换为像素坐标时缩放数据。
我所看到的完全是太多次了,因为图表由点和线组成,人们将建立一个由点对象和线对象组成的数据结构,每个对象都有DrawMyself,然后使得持久化,在理论认为,这种方式“更有效”,或者它们可能只需要能够鼠标悬停在图表的某些部分上并以数字方式显示数据,因此他们将方法构建到对象中以处理它,并且当然,涉及创建和删除更多的对象。
所以你最终会得到大量的代码,这些代码非常易读,只花费90%的时间管理对象。
所有这些都是以“良好的编程实践”和“效率”的名义完成的。
至少在C语言中,简单有效的方式会更加明显,并且建造金字塔的诱惑力也会降低。
答案 3 :(得分:11)
GNU coding standards已经发展了几十年。阅读它们是个好主意,即使你不遵循它们。考虑到它们中提出的要点,可以为您构建自己的代码奠定更坚实的基础。
答案 4 :(得分:3)
我建议你查看任何流行的开源C项目的代码,比如...嗯...... Linux内核,或者Git;并了解他们如何组织它。
答案 5 :(得分:3)
复杂应用程序的编号规则:它应该易于阅读。
为了简化复杂的应用程序,我使用了Divide and conquer。
答案 6 :(得分:3)
如果您知道如何使用Java或C ++构建代码,那么您可以使用与C代码相同的原则。唯一的区别是你没有自己的编译器,你需要手动更加小心。
由于没有包和类,您需要从仔细设计模块开始。最常见的方法是为每个模块创建单独的源文件夹。您需要依赖命名约定来区分不同模块之间的代码。例如,使用模块名称为所有函数添加前缀。
您不能拥有C类,但您可以轻松实现“抽象数据类型”。您为每个抽象数据类型创建.C和.H文件。如果您愿意,可以有两个头文件,一个是公共文件,另一个是私有文件。这个想法是需要导出的所有结构,常量和函数都转到公共头文件。
您的工具也非常重要。 C的一个有用工具是lint,它可以帮助您在代码中找到难闻的气味。您可以使用的另一个工具是Doxygen,它可以帮助您生成documentation。
答案 7 :(得分:3)
无论开发语言如何,封装始终是成功开发的关键。
我用来帮助在C中封装“私有”方法的一个技巧是不将它们的原型包含在“.h”文件中。
答案 8 :(得分:2)
我建议您阅读C / C ++教科书作为第一步。例如,C Primer Plus是一个很好的参考。通过这些示例,您可以了解如何将Java OO映射到更像C语言的过程语言。