我只有初学者级别的C技能,并想知道是否有任何事实上的"标准"来构建C中有点复杂的应用程序.甚至基于GUI的应用程序.
我一直在Java和PHP中使用OO范例,现在我想学习C我害怕我可能以错误的方式构建我的应用程序.我无法遵循哪些指导方针,使用程序语言实现模块化,解耦和干燥.
你有任何建议吗?我找不到C的任何应用程序框架,即使我不使用框架,我总是通过浏览他们的代码找到好的想法.
关键是模块化.这更容易设计,实现,编译和维护.
识别应用中的模块,例如OO应用中的类.
每个模块的独立接口和实现,仅在接口中放入其他模块所需的接口.请记住,C中没有命名空间,因此您必须使接口中的所有内容都是唯一的(例如,使用前缀).
在实现中隐藏全局变量并使用访问器函数进行读/写.
不要考虑继承,而是考虑构成.作为一般规则,不要试图在C中模仿C++,这将非常难以阅读和维护.
如果您有时间学习,请查看Ada应用程序的结构,包括强制package
(模块接口)和package body
(模块实现).
这是为了编码.
为了维护(记住你编码一次,但你保持了几次)我建议记录你的代码; Doxygen对我来说是一个不错的选择.我建议还要建立一个强大的回归测试套件,它允许你重构.
这是一种常见的误解,即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" */
所有好的答案.
我只会添加"最小化数据结构".这甚至可能会在C更容易,因为如果C++是"带类的C",OOP正试图鼓励你们采取一切名词/动词在你的头上,并把它变成一个类/方法.这可能非常浪费.
例如,假设您在某个时间点有一系列温度读数,并且您希望在Windows中将它们显示为折线图.Windows有一条PAINT消息,当你收到它时,你可以循环执行LineTo函数的数组,在你将数据转换为像素坐标时缩放数据.
我所看到的完全过很多次,由于图由点和线,人们将建立一个数据结构,其中包括点对象和线对象,每一个都能够DrawMyself的,然后作出这样的执着,从理论上说是是某种"更有效",或者他们可能,只是可能,必须能够将鼠标指向图表的零件和数字显示的数据,所以他们建立方法引入的对象来处理了,并且,当然,涉及创建和删除更多对象.
因此,您最终会得到大量的代码,这些代码非常易读,而且仅花费90%的时间来管理对象.
所有这些都是以"良好的编程实践"和"效率"的名义完成的.
至少在C中,简单,有效的方式将更加明显,并且建造金字塔的诱惑力不那么强烈.
在GNU编码标准已经发展了几十年.阅读它们是个好主意,即使你不遵循它们.考虑到它们中提出的要点,可以为您构建自己的代码提供更坚实的基础.