Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design Principles, Best Practices and Design Patterns for C (or Procedural Programming in general)? [closed]

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?

(I'm child of the 'object-oriented generation' and have to design a large C project for the first time)

like image 203
Dimi Avatar asked Mar 22 '10 13:03

Dimi


People also ask

What are design principles in programming?

Software Design Principles are a set of guidelines that helps developers to make a good system design. In the development process, the time for writing code will only consume from 20 to 40 percent, remaining we will read code and maintain the system. So, Making a good system design is very important.

Are there any design patterns in C?

Yes, there are. Lazy initialization, singleton, object pool, object state etc. are easily implemented in pure C.

What is the best approach in designing patterns in coding?

One of the most popular design patterns used by software developers is a factory method. It is a creational pattern that helps create an object without the user getting exposed to creational logic. The only problem with a factory method is it relies on the concrete component.

What is C pattern design?

Design Patterns in the object-oriented world is a reusable solution to common software design problems that occur repeatedly in real-world application development. It is a template or description of how to solve problems that can be used in many situations. "A pattern is a recurring solution to a problem in a context."


2 Answers

Information hiding - as espoused by Parnas (Software Fundamentals).

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.

like image 61
Jonathan Leffler Avatar answered Sep 27 '22 18:09

Jonathan Leffler


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.

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; } 
like image 44
Itay Maman Avatar answered Sep 27 '22 20:09

Itay Maman