Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recommendations for 'C' Project Architecture Guidelines? [closed]

Tags:

Now that I got my head wrapped around the 'C' language to a point where I feel proficient enough to write clean code, I'd like to focus my attention on project architecture guidelines. I'm looking for a good resource that coves the following topics:

  1. How to create an interface that promotes code maintainability and is extensible for future upgrades.
  2. Library creation guidelines. Example, when should I consider using static vs dynamic libraries. How to properly design an ABI to cope with either one.
  3. Header files: what to partition out and when. Examples on when to use 1:1 vs 1:many .h to .c
  4. Anything you feel I missed but is important when attempting to architect a new C project.

Ideally, I'd like to see some example projects ranging from small to large and see how the architecture changes depending on project size, function or customer.

What resource(s) would you recommend for such topics?

like image 265
SiegeX Avatar asked May 08 '10 00:05

SiegeX


2 Answers

Whenever I got serious writing C code, I had to emulate C++ features in it. The main stuff worth doing is:

  • Think of each module like a class. The functions you expose in the header are like public methods. Only put a function in the header if it part of the module's needed interface.

  • Avoid circular module dependencies. Module A and module B should not call each other. You can refactor something into a module C to avoid that.

  • Again, following the C++ pattern, if you have a module that can perform the same operations on different instances of data, have a create and delete function in your interface that will return a pointer to struct that is passed back to other functions. But for the sake of encapsulation, return a void pointer in the public interface and cast to your struct inside of the module.

  • Avoid module-scope variables--the previously described pattern will usually do what you need. But if you really need module-scope variables, group them under a struct stored in a single module-scope variable called "m" or something consistent. Then in your code whenever you see "m.variable" you will know at a glance it is one of the module-scope structs.

  • To avoid header trouble, put #ifndef MY_HEADER_H #define MY_HEADER_H declaration that protects against double including. The header .h file for your module, should only contain #includes needed FOR THAT HEADER FILE. The module .c file can have more includes needed for the compiling the module, but don't add those includes into the module header file. This will save you from a lot of namespace conflicts and order-of-include problems.

like image 187
Erik Hermansen Avatar answered Oct 03 '22 11:10

Erik Hermansen


The truths about architecting systems are timeless, and they cross language boundaries. Here is a little advice focused on C:

  • Every module hides a secret. Build your system around interfaces that hide information from their clients. C's only type-safe information-hiding construct is the pointer to an incomplete structure. Learn it thoroughly and use it often.

  • One interface to an implementation is a good rule of thumb. (Interface is .h, implementation is .c.) Sometimes you will want to provide two interfaces that relate to the same implementation: one that hides the representation and one that exposes it.

  • You'll need naming conventions.

A superb model of how to handle these kinds of problems in C is Dave Hanson's C Interfaces and Implementations. In it you will get to see how to design good interfaces and implementations, and how one interface can build on another to form a coherent library. You will also get an excellent set of starter interfaces you can use in your own applications. For someone in your position, I cannot recommend this book too highly. It is an archetype of well-architected systems in C.

like image 27
Norman Ramsey Avatar answered Oct 03 '22 13:10

Norman Ramsey