I come from a java background (from my CS classes) and a semester of C++. I am just finishing up a OpenCV project for my Co-Op that's in pure C, so I'm a bit late in asking this question.
What are the design processes and coding standards for pure C?
I'm familiar with object oriented programming, design and best practices. I'm just a bit at a loss at a non-object oriented language like C. Every single variable and function appears to be global. It makes it feel like a real mess to me.
I honestly don't think that any number of answers on StackOverflow are going to teach you how to design and write well-structured C programs. You need to read a good book, and the obvious one to read is The C Programming Language by Kernighan & Ritchie.
You can restrict visibility of file-scope variables and functions to their respective source files (although that doesn't prevent you from passing pointers to these objects around).
For example:
I have no professionnal experience on C (only on C++), so don't take my advices, tricks and tips too seriously, as they are "object-like-oriented".
Almost Object C?
Simulating basic object-like features can be done easily:
In the header, forward declare your type, typedef it, and declare the "methods". For example:
You'll see each functions is prefixed. I choose the name of the "struct" to make sure there won't be collision with another code.
You'll see, too, that I used "p_pThis" to keep with the OO-like idea.
In the source file, define your type, and define the functions:
If you want "private" functions (or private global variables), declare them static in the C source. This way, they won't be visible outside:
If you want inheritance, then you're almost screwed. If you believed everything in C was global, including variable, then you should get more experience in C before even trying to think how inheritance could be simulated.
Misc. Tips
Avoid multiple code-paths.
For example, multiple returns is risky. For example:
Avoid non-const globals
This include "static" variables (which are not static functions).
Global non-const variables are almost always a bad idea (i.e. see C API strtok for an example of crappy function), and if producing multithread safe code, they are a pain to handle.
Avoid name collision
Choose a "namespace" for your functions, and for your defines. This could be:
Beware defines
Defines can't be avoided in C, but they can have side effects!
Initialize your variables
Avoid declaring variables without initializing them:
Uninitialized variables are causes of painful bugs.
Know all the C API
The C API function list as described in the K&R is quite small. You'll read the whole list in 20 minutes. You must know those functions.
Wanna some experience?
Rewrite the C API. For example, try to write your own version of the string.h functions, to see how it is done.
Work with other good C programmers. Have a code review with them. Not only let them look at your code, but you look at their code.
You may want to have a good look at the source of The Linux Kernel..... BTW it is not the easiest piece of code to start with but since you are from a programming background, it may help... As an object-oriented programmer, you might particularly find error-handling in C an uphill task. May be this helps---> http://www.freetype.org/david/reliable-c.html
You can do object oriented design in pure C. An easy approach is to think of a module as a
class
with public methods as ordinary functions that require thethis
parameter as an explicit first argument.It helps if the
class
name is a prefix on the function name, and if all private functions and class data are declaredstatic
. You build constructors withmalloc()
to get the memory, and explicit initialization of the data fields.A constructor for an object with entirely private data members can expose an opaque pointer (typed
void *
even, or as a pointer to an incomplete type if type safety is desired). If you want to have only public data members, then a pointer to a publicly definedstruct
works well.This pattern is followed by a number of libraries. An initialization function returns a cookie that must be passed back to all library methods, and one method serves as a destructor.
Of course, there are other ways to design well in pure C, but if OO works for you, you don't have to abandon it completely.