我应该如何在C中构建复杂的项目?[关闭]


79

我只具备初学者级C技能,并且想知道是否存在任何事实上的“标准”来在C中构建一个稍微复杂的应用程序。甚至包括基于GUI的应用程序。

我一直在Java和PHP中使用OO范例,现在我想学习C语言,恐怕会以错误的方式构造应用程序。我不知所措,要遵循哪些准则以程序语言实现模块化,去耦和干燥。

你有什么建议吗?我找不到C的任何应用程序框架,即使我不使用框架,我也总是通过浏览它们的代码找到不错的主意。


3
Unix哲学对于组织大型项目非常有用:http
newDelete 2012年

Answers:


51

关键是模块化。这更易于设计,实现,编译和维护。

  • 识别应用程序中的模块,例如OO应用程序中的类。
  • 每个模块都有单独的接口和实现,仅将其他模块需要的接口放入接口。请记住,C中没有名称空间,因此您必须使接口中的所有内容都是唯一的(例如,带前缀)。
  • 在实现中隐藏全局变量,并使用访问器函数进行读/写。
  • 不要考虑继承,而要考虑组成。通常,不要尝试在C中模仿C ++,这将很难阅读和维护。

如果您有时间学习,请查看Ada应用程序的结构,以及其强制性package(模块接口)和package body(模块实现)。

这是用于编码。

为了维护(请记住,您编写了一次代码,但是您维护了几次),我建议记录您的代码。Doxygen对我来说是一个不错的选择。我建议您还建立一个强大的回归测试套件,以便您进行重构。


30

常见的误解是,OO技术不能在C语言中应用。大多数都可以-只是它们比使用专用于该语法的语言稍微笨拙。

健壮的系统设计的基础之一是在接口后面封装实现。 FILE*和功能与它(工作fopen()fread()等)是如何封装可以在C被施加到接口建立一个很好的例子。(当然,由于C缺少访问说明符,因此您不能强制A中没有人偷看struct FILE,而只有受虐狂才可以这样做。)

如有必要,可以使用函数指针表在C中实现多态行为。是的,语法丑陋,但效果与虚函数相同:


11
一个纯C编码器会在阅读此代码时迷路……
mouviciel

15
@mouviciel:垃圾!大多数C程序员都理解函数指针(或者至少他们应该理解),并且除了这里没有真正的事情发生。至少在Windows上,设备驱动程序和COM对象都以这种方式提供其功能。
j_random_hacker

8
我的意思不是无能,而是不必要的并发症。函数指针对于C编码器(例如,回调)是通用的,而继承不是。我更喜欢用C进行编码的C ++编码器要花费更多的时间来学习C,而不是构建伪C ++类。也就是说,您的方法在某些情况下可能有用。
mouviciel

3
实际上,您甚至可以使用C ++ pimpl习惯用法来模拟访问说明符。如果将类型的私有成员封装为仅在实现中可见的类型(也称为“ .c文件”),则接口的用户将很难更改它们(当然,他们可以将垃圾写入pimpl指针,如果他们想故意把你弄糟的话,但是你可以在C ++中做同样的事情。
bitmask

2
唐纳德:想发表评论吗?
j_random_hacker 2013年

15

所有好的答案。

我只会添加“最小化数据结构”。在C语言中,这甚至可能更容易,因为如果C ++是“带类的C”,那么OOP会试图鼓励您将脑海中的每个名词/动词转换为类/方法。那可能非常浪费。

例如,假设您在某个时间点具有一系列温度读数,并且希望将其显示为Windows中的折线图。Windows收到一条PAINT消息,当您收到消息时,可以遍历执行LineTo函数的数组,并在缩放数据时将其转换为像素坐标。

我完全看过太多次了,由于图表由点和线组成,人们将建立一个由点对象和线对象组成的数据结构,每个对象都具有DrawMyself的功能,然后根据以下理论使其持久化:是某种程度上“更有效率”,或者也许只是必须能够将它们悬停在图表的各个部分上并以数字方式显示数据,因此他们将方法内置到对象中以进行处理,当然,涉及创建和删除更多对象。

因此,您最终将获得大量易于​​理解的代码,仅花费90%的时间来管理对象。

所有这些都是以“良好的编程习惯”和“效率”的名义完成的。

至少在C语言中,简单,有效的方式会更加明显,而建立金字塔的诱惑力也不会那么强。


1
爱你的答案,这是完全正确的。OOP必须死!
乔苏因此

@JoSo:我使用OOP,但最少。
Mike Dunlavey

对我而言,“至少”(尽管我不知道这对您意味着什么)并不真正算作OOP,它是面向对象编程-默认情况下为对象。
乔·

我也使用一些“ OOP”。主要用于我的C模块,其中许多模块具有init()和exit()例程。
乔·

11

GNU编码标准已经发展了几十年。最好阅读它们,即使您不遵循它们。考虑它们中提出的要点,可以为您如何构建自己的代码提供更牢固的基础。


4
不是所有人都喜欢它们,来自lxr.linux.no/linux+v2.6.29/Documentation/CodingStyle:“首先,我建议打印出GNU编码标准的副本,而不要阅读它。将它们刻录,这是一个伟大的象征性姿态”。我已经很多年没有读过它们了,但是Linus有一些有效的反对意见。
hlovdal

1
@hlovdal:当然,并不是每个人都喜欢任何一种特定的编码标准,这就是为什么类似用例有多个标准的原因。重要的是,您必须在自己的项目中保持一致,至少要遵循一些标准,而不是事实上的临时不一致。
JM Becker 2014年

4

如果您知道如何用Java或C ++构造代码,则可以对C代码遵循相同的原理。唯一的区别是您不需要编译器,并且需要手动做所有事情。

由于没有包和类,因此需要首先仔细设计模块。最常见的方法是为每个模块创建一个单独的源文件夹。您需要依靠命名约定来区分不同模块之间的代码。例如,所有功能都以模块名称作为前缀。

您不能使用C编写类,但可以轻松实现“抽象数据类型”。您为每种抽象数据类型创建一个.C和.H文件。如果愿意,可以有两个头文件,一个是公共文件,另一个是私有文件。这个想法是所有需要导出的结构,常量和函数都将进入公共头文件。

您的工具也非常重要。C语言有用的工具是lint,它可以帮助您在代码中发现难闻的气味。您可以使用的另一个工具是Doxygen,它可以帮助您生成文档


4

无论开发语言如何,封装始终是成功开发的关键。

我用来帮助在C中封装“私有”方法的一个技巧是不将其原型包含在“ .h”文件中。




2

我建议第一步阅读C / C ++教科书。例如,C Primer Plus是一个很好的参考。浏览这些示例将使您和如何将Java OO映射到更具过程性的语言(如C)的想法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.