C语言 C(或一般的过程编程)的设计原则、最佳实践和设计模式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2492446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Design Principles, Best Practices and Design Patterns for C (or Procedural Programming in general)?
提问by Dimi
Are there any known design principles, best-practices and design patterns that one can follow while designing a C project? Or useful design principles for procedural (imperative) programming in general?
在设计 C 项目时,是否有任何已知的设计原则、最佳实践和设计模式可以遵循?或者一般的过程(命令式)编程有用的设计原则?
(I'm child of the 'object-oriented generation' and have to design a large C project for the first time)
(我是“面向对象一代”的孩子,必须第一次设计一个大型 C 项目)
采纳答案by Jonathan Leffler
Information hiding - as espoused by Parnas (Software Fundamentals).
信息隐藏 - 正如 Parnas(软件基础知识)所支持的那样。
Careful management of headers and visibility:
仔细管理标题和可见性:
- Everything in a source file that can be hidden from the outside world should be; only the documented external interface should be exposed.
- Everything that is exposed is declared in a header.
- That header is used where the functionality is needed (and where it is defined).
- The header is self-contained - when you need it, you use it, and you don't have to fret about 'what other headers do I also have to include' because the header ensures it works by including anything it needs to make it work.
The header is self-protected - so it does not matter if it is included multiple times.
#ifndef HEADER_H_INCLUDED #define HEADER_H_INCLUDED ...rest of header contents, including other #include lines if necessary #endif /* HEADER_H_INCLUDED */Design sets of functions to work on 'objects' (usually structures) - and use those functions rather than poking around the innards of the structure in the code that is using it. Think of it as self-imposed encapsulation.
- 源文件中可以对外界隐藏的所有内容都应该是;只应公开记录在案的外部接口。
- 公开的所有内容都在标头中声明。
- 该标头用于需要功能的地方(以及定义它的地方)。
- 标头是独立的——当你需要它时,你可以使用它,而且你不必担心“我还必须包含哪些其他标头”,因为标头通过包含它需要的任何内容来确保它正常工作工作。
标头是自我保护的 - 所以它是否被多次包含并不重要。
#ifndef HEADER_H_INCLUDED #define HEADER_H_INCLUDED ...rest of header contents, including other #include lines if necessary #endif /* HEADER_H_INCLUDED */设计一组处理“对象”(通常是结构)的函数——并使用这些函数,而不是在使用它的代码中探查结构的内部结构。将其视为自我强加的封装。
回答by Itay Maman
My three advices:
我的三个建议:
- Write unit tests. They will help you zero in on a design that suites your problem as you go along. Much better than relying (solely) on pre-meditated thinking.
- Have a memory leak detector (there are all sort of libraries out there) installed and running from day one. Have this library print out all leaks as soon as the program/tests exits. This will allow you to catch a leak as soon as you introduce it, thereby making its fixing much less painful.
- Write OOP code in C. Not that difficult. While it is possible to emulate method overriding, I suggest that you start with emulation of simple objects. Even this simple mechanism can give you great mileage.
- 编写单元测试。他们将帮助您将设计归零,以适应您的问题。比(仅)依赖预先思考的思维要好得多。
- 从第一天起安装并运行内存泄漏检测器(那里有各种库)。一旦程序/测试退出,就让这个库打印出所有泄漏。这将使您在引入泄漏后立即发现泄漏,从而减少修复的痛苦。
- 用 C 编写 OOP 代码。没那么难。虽然可以模拟方法覆盖,但我建议您从模拟简单对象开始。即使是这种简单的机制也可以为您带来巨大的里程。
Here's an example:
下面是一个例子:
typedef struct Vector {
int size;
int limit;
int* ints;
} Vector;
Vector* Vector_new() {
Vector* res = (Vector*) malloc(sizeof(Vector));
res->limit = 10;
res->size = 0;
res->ints = (int*) malloc(sizeof(int) * res.limit);
return res;
}
void Vector_destroy(Vector* v) {
free(v->ints);
free(v);
}
void Vector_add(Vector* v, int n) {
if(v->size == v->limit) {
v->limit = v->limit * 2 + 10;
v->ints = realloc(v->ints, v->limit);
}
v->ints[v->size] = n;
++v->size;
}
int Vector_get(Vector* v, int index) {
if(index >= 0 && index < v->size)
return v->ints[index];
assert false;
}
回答by e.James
There is a good, free, online book, titled Object-Oriented Programming With ANSI-C, which covers the topic of writing object-oriented code in C. A google searchfor "object-oriented C" also yields a number of other good examples and resources.
有一本不错的免费在线书籍,标题为Object-Oriented Programming With ANSI-C,它涵盖了用 C编写面向对象代码的主题。谷歌搜索“面向对象的 C”也产生了许多其他好的示例和资源。
If your project is safety-critical, MISRA-Cis a good set of rules. It is intended mostly for embedded c, but it can be useful in other areas as well.
如果您的项目对安全至关重要,那么MISRA-C是一套很好的规则。它主要用于嵌入式 c,但它也可用于其他领域。
I consider myself an OO coder, and I do a lot of work with embedded-C. The best advice I can give, especially for large projects, is not to overdo it. Creating a complete OO framework on top of ANSI C can be very tempting, but it takes a great deal of time and effort to get it right. The fancier you get, the more time you will spend debugging your framework instead of working on the realproject. Approach the task with a clear head, and a good, solid grasp of YAGNI. Best of luck!
我认为自己是一个面向对象的编码员,我用嵌入式 C 做了很多工作。我能给出的最好建议,尤其是对于大型项目,不要过度。在 ANSI C 之上创建一个完整的 OO 框架可能非常诱人,但需要花费大量的时间和精力才能做到正确。你越喜欢,你花在调试框架上而不是在真正的项目上的时间就越多。以清醒的头脑和对YAGNI的良好、扎实的掌握来处理任务。祝你好运!
回答by e.James
OOP is a methodology not a technology. So my first bit of advice is stop thinking of it as procedural programming.
OOP 是一种方法论,而不是一种技术。所以我的第一条建议是不要将其视为过程式编程。
To e.James's point, you don't want to try and re-create an object-oriented language or pretend that you have the capabilities thereof. You can still do all the right things by clinging to a few simple principles:
就 e.James 的观点而言,您不想尝试重新创建面向对象的语言或假装您拥有该语言的功能。通过坚持一些简单的原则,您仍然可以做所有正确的事情:
- Test drive everything.
- Find what varies and encapsulate it.
- Design to interfaces.
- 试驾一切。
- 找出变化的内容并将其封装起来。
- 设计到接口。

