Design Patterns in C?

Asked

Viewed 1,688 times

12

I’ve initiated the development of a system embedded in pure C. The project requires detailed documentation of software and hardware, as well as using the recommended design standards. It is known that there are several project standards aimed at methods, classes, packages and the like of object-oriented programming. What about C? In my case I will create the header files . h and the implementation files themselves . c.

I read in some places that the default for C is the declaration of the functions at the beginning of the file and the implementation just below the declarations, getting:

void funca1(int arg1, int arg2);
int funca2(bool arg1, int arg2);
...
void funca1(int arg1, int arg2){
// code here...
}

int funca2(bool arg1, int arg2){
// code here
}

That’s all there is to C?

  • The usual extension for C language is .c (and not .cpp as indicas).

  • @pmg was a typo, cpp is from C++?

  • It’s C++ ’s yes .cpp. The idea is to have the signatures of the functions in the .h and their implementation in .c

  • 1

    Your question is very good, but a very broad one. I thought to offer an answer, but after I started writing it seemed opinionated ("my choices") and vast. I suggest you create questions for specific principles (this one may be regarding the motivation/purpose/advantage of using/defining signatures/prototypes of functions).

  • 1

    Also, I suggest you look for material using the expression "best practices" (or "best practices", if you search in English) rather than "design patterns". It’ll help you out a little bit. Especially, this blog has a lot of cool stuff quite arguable, as for example this article on 5 common practices (and the argument of how to make them really better).

  • 1

    I understand Luiz, in this case the need is due to generate the same product documentation.

  • 1

    Ah, I see what you mean. I’m sorry, I didn’t understand this because of the apparent focus on function signatures. Well, there is still much that can be done about it: graphs with the connection between the "modules" of your system, detailing the dependencies between the functions (who calls who), and so on. If I can come up with an answer I’ll offer it later. :)

  • @touchmx http://answall.com/a/16204/101 This reply of mine may interest you to reinforce and give another explanation that patterns are something recognized and recurrent, as Luiz Viera’s excellent answer says.

Show 3 more comments

2 answers

15


As I have already commented, this is a great question, although a little difficult because it can be addressed in some different ways. There are a very similar question (if not exactly the same) in SOEN. I don’t know if you already knew her or if you inspired her, but surely the content there will also help you.

About the use of Standards for Documentation

As its name says, the Project Standards (Design Patterns) are recurring problem profiles accompanied by well-used, tested and assessed solution approaches to the problems they propose to solve. Naturally its primary use (i.e., originally intended) is to facilitate the solution of recurring problems. A designer who has studied Design Standards and recognizes a well-described problem can quickly utilize the best approach, and thus decrease coupling, facilitate maintenance, etc, etc., etc.

But naturally the Project Standards also serve to assist in the documentation of systems. After all, if the solutions employed are standardized approaches and widely recognized by the community, the mere mention of them will help a lot. For example:

The game XXXXXX uses the pattern Bridge the rendering of obstacles, in order to separate the design from the shape (circular, triangular, quadrilateral, etc.) of the line used in the drawing (continuous, dashed, punctuated, blinking, etc.).

In this example scenario, any new developer who arrives at the project and you already know the standard Bridge will have a good idea of how the implementation was made, and will know that in the need to create a new format (hexagonal, for example) it will be enough to inherit the base class of the formats to automatically be able to reuse in it all the existing strokes.

Thinking this way, the difficulty of documentation is not in the design pattern itself, but in its formal description and in its recognition by a community. The gof design patterns, for example, they were created and documented in a standardized format that includes the following descriptions:

  • Name. The name of the project pattern, which serves as a unique identifier for easy reference.
  • Intention. The purpose of this pattern, that is, why it exists, what is its usefulness, what kind of advantages it brings.
  • Problem. The problem that the standard proposes to solve. This description includes not only text, but also diagrams, examples and whatever else helps to make understanding of the problem broad and widespread (after all, problems can recur regardless of the domain of the system).
  • Solution. How the standard provides solution to the problem. Again, here you can also include text, diagrams and examples, with the intention of describing in detail how this implementation occurs.
  • Participants and Collaborators. The entities involved in the solution and how they represent parts of the problem. Gof originally mentioned the classes involved, but entities can be entities like any computationally deployable structures in the language/technology used.
  • Consequences. Description of possibilities arising from the use of the standard, including potential problems avoided, ease of evolution, interaction with other patterns, etc.

It is my opinion (and I would like to make it very clear that this part is really an opinion, although based on experience) that any design approach that serves as a solution and was created by you yourself can be documented in a similar way. That’s why I suggested you in comments to look for "best practices". Best practices are still standardized solutions for recognized problems, commonly described verbatim and with code examples.

In fact, Gof himself indicates that elements of the object-oriented approach could be considered design patterns in the C language (citation-free translation text in this SOEN response):

"The choice of programming language is important because it influences the programmer’s point of view. Our standards assume languages with Smalltalk/C++ level characteristics, and this choice determines what can and cannot be implemented easily. If we assume procedural languages, we could include as standards from project to "Heritage", the "Encapsulation" and the "Polymorphism". Of similarly, some of our standards are directly supported by less object-oriented languages. CLOS has multi-methods, by example, which decrease the need for standards such as Visitor."

The italics are mine.

Existing Standards in C

Certainly there are existing design patterns for the C language, well documented and widely known. The most popular ones are those of the book "Patterns in C" by Adam Tornhill (His name was Adam Petersen before he got married and changed his last name). The answer accepted from the SOEN question that I referenced at the beginning has links to chapters of his book, but I would suggest buying it because it is not expensive ($4.99 is the minimum value for the digital version on his site) and stimulates the good work of people like him.

In this book you find, for example, the pattern First-Class ADT, which separates the "interface" (which is publicly accessible) from the implementation of "objects" (pointers to structures). The idea is quite simple: you use the characteristics of being able to declare incomplete types in the C language to define a pointer to the structure and provide functions to allocate and displace the actual structure, thus hiding direct access to the elements of the structure. There is also, for example, the pattern States, which uses a state transition table to avoid repeating (potentially long) decision structures every time the state variable needs to be checked. This pattern, although documented for use in C, is closely related to the same problem that can occur in C++, as already well documented here at SOPT.

As I’ve opined before, I think design standards need not only include solutions to higher-level problems, but also recognized solutions that aim to avoid low-level implementation problems (compilation errors, memory access failures, data type difficulties, etc.). In that case, I repeat the suggestion I offered in comments: best practices are very useful when documented, because they not only describe the idealized approach as a standard for the team of developers but also motivate them to think about the potential problems in not using them.

Notable examples (though often still discussed) are the use of definitions (#define) to avoid circular inclusion of headers, the use of const instead of #define to define constant values, and also avoid the use of scanf to decrease memory invasion errors.

P.S.: Note how in the @pmg response there is the use of one of these patterns cited. The #ifndef HEADER_H_INCLUDED serves precisely to prevent the circular header inclusion. :)

  • 1

    Your answer is extremely enlightening to me. Your approach gives me an impression of great experience and knowledge in the field of engineering. I am very grateful for your time and response. If it were possible I would vote a thousand times in your reply.

  • Thanks, but once is enough. : ) I’m happy to help.

8

With regard to header files, code files and prototypes' location, the most convenient is to get the prototypes into the .h and include that .h in the .c. So you only write each prototype once ... and the compiler checks to see if the prototype matches the definition when compiling.

For example, the "Foobar. h header file"

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
void foo(int);
int bar(void);
#endif

and the source file "Foobar. c"

#include "foobar.h"

int foo(int n) {
    return n + 42;
}
int bar(int n) {
    return n + 42;
}

When you compile "Foobar. c" the compiler will check the functions and give error (or Warning) because the prototype does not match the definition.

Note: set your compiler to maximum warnings and try to make code Compile with 0 warnings.

  • Excellent, well summarized and with the whole thingy. It made only a reference also the structures.

  • In this case it is only that that exists for the development in C and other languages that use the structured paradigm?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.