tags:

views:

618

answers:

8

Coming from a OO background (C#/java) I'm looking for resources to learn how to design pure C programs well.

Whilst i'm familiar with the syntax of C, and i can write small programs, i'm unsure of the approach to take for larger applications, and what techniques to employ. Anything you guys can recommend.

EDIT: I'm happy to completly abandon OO for the purposes of programming in C, my interest is in learning how to structure a program without OO, I want to learn about good ways of designing programs in procedural languages such as C.

+2  A: 

Here's some interesting responses from a different question regarding OO programming in C. I made a post about some C code I worked with which basically impelmented object orientation stopping just short by not including virtual methods.

If I were doing C coding, I would use this technique to define 'objects'.

I find keeping Design Patterns in mind is always helpful, and can be implemented in most languages.

Here's a nice PDF discussing object oriented C programming.

Kieveli
If you want to do OO in C, you should really use C++. If you want to use C, you should write nice, clear procedural code.
Chris Lutz
"If you want to use C, you should write nice, clear procedural code."Would you be able to recommend any resources to learn how to do this? This is the kind of thing i'm looking for.
docflabby
There are cases where using C is required. Not all processors have C++ compilers - especially if you're moving into an embedded situation. When you're working with code to run on low-level hardware, it's still in your best interest to code it in C, and then have a C++ wrapper.
Kieveli
OOP in C mostly boils down to implementing objects as structures and methods as standalone functions with an explicit instance pointer parameter. This is similar to how other languages tackle OOP, so that you call METHOD(object, arg1, arg2 ...).Of course, using function pointers you could also implement the more common obj.method(arg1,arg2) approach.
none
If you skip using function pointers, and go with the method of passing in the object struct pointer, then you leave the code way more readable =)
Kieveli
+1  A: 

minix by tanenbaum

Peter Miehle
+16  A: 

This posting has a list of unix books which includes most of the classic C/Unix books. For C programming on Windows, Petzold is probably the best start.

For C program design, some of the unix programming books will tell you snippets but I'm not aware of a 'C program architecture' book.

If you're used to java, some tips for C programing are:

  1. Make use of the stack. Often when you call a procedure you will want to have variables allocated in the caller's stack frame and pass pointers to them into the procedure you want to call. This will be substantially faster than dynamically allocating memory with malloc() and much less error prone. Do this wherever appropriate.

  2. C doesn't do garbage collection, so dynamically allocating data items is more fiddly and you have to keep track of them to make sure they get freed. Variables allocated on the stack (see 1) are more 'idiomatic' where they are applicable. Plus, you don't have to free them - this is a bonus for local variables.

  3. Apropos of (2), consider an architecture where your functions return a status or error code and pass data in and out using the stack as per (1).

  4. Get to know what setjmp() and longjmp() do. They can be quite useful for generic error handler mechanisms in lieu of structured exception handling functionality.

  5. C does not support exceptions. See (3).

  6. Lint is your friend. Splint is even friendlier.

  7. Learn what the preprocessor does and what you shouldn't do with it even if you can.

  8. Learn the ins and outs of endian-ness, word alignment, pointer arithmetic and other low-level architectural arcana. Contrary to popular opinion these are not rocket science. If you're feeling keen, try dabbling in assembly language and get a working knowledge of that. It will do much for your understanding of what's going on in your C program.

  9. C has no concept of module scope, so plan your use of includes, prototype declarations, and use of extern and static to make private scopes and import identifiers.

  10. GUI programming in C is tedious on all platforms.

  11. Apropos of (10) learn the C API of at least one scripting language such as Tcl, Lua or Python. In many cases the best use of C is as a core high-performance engine on an application that is substantially written in something else.

  12. C/Unix books, even really good ones like the ones written by the late W Richard Stevens tend to be available secondhand quite cheaply through Amazon marketplace. In no particular order, get a copy of K&R, Stevens APUE and UNP 1 & 2, the Dragon book, Rochkind, Programming Pearls, Petzold abd Richter (if working on Windows) and any of the other classic C/Unix works. Read, scribble on them with a pencil and generally interact with the books.

  13. There are many, many good C/Unix programming resources on the web.

  14. Read and understand the Ten Commandments of C Programming and some of the meta discussion as to the why's and wherefores behind the commandments. This is showing its age to a certain extent, although most of it is still relevant and obscure compilers are still quite common in the embedded systems world.

  15. Lex and Yacc are your friend if you want to write parsers.

  16. As Navicore points out below (+1), Hanson's 'C Interfaces and Implementations' is a run-down on interface/implementation design for modular architecture with a bunch of examples. I have actually heard of this book and heard good things about it, although I can't claim to have read it. Aside from the C idioms that I've described above, this concept is arguably the core of good procedural design. In fact, other procedural languages such as Modula-2 actually make this concept explicit in their design. This might be the closest thing to a 'C Program Architecture' book in print.

ConcernedOfTunbridgeWells
These are definitely some good bullet points. I'm surprised to see setjmp and longjmp mentioned so prominently. While powerful, use of these two should be pretty rare, no? If you think abuse of goto is bad (most people seem to), imagine abuse of setjmp and longjmp (yikes!). As for assmebly, I'd add that it's important to not just dabble in writing your own assembly, but also to analyze the assembly generated by the C compiler to get an understanding of what's really going on.
Dan Moulding
Setjmp does a bit more than goto. It squirrels away the local context of the function. You would normally use it to build generic error handlers in lieu of a structured exception mechanism. The advice is to understand how this mechanism works.
ConcernedOfTunbridgeWells
In C there is no exceptions like in Java, and using goto to implement something similar is the right thing to do.
hlovdal
lol @ #10. Amen.
Justicle
A: 

stay away from the gcc source code ;-)

none
+2  A: 

My concerns going from OO back to C were addressed in David Hanson's "C Interfaces and Implementations".

C Interfaces and Implementations

Seriously, its approach made a huge difference in avoiding accidentally building the large ball of yarn that many non-oo systems wind up as.

navicore
+1 - thanks for reminding me. I have heard of this book but I've never read it. Interfaces/implementations is a key procedural methodology and is made explicit in Modula-2. Will point to this in my post as I think this may be the the closest thing to a 'C architecture' book I've ever heard of. Good thinking 99 ;-}
ConcernedOfTunbridgeWells
A: 

While it is written as a somewhat language-agnostic text, Code Complete provides a lot of good guidance on code structure and organization, along with construction practices.

Novelocrat
A: 

Larger applications? C's strength is when you have to deal with low level things like device drivers, schedulers, and other OS flavored things.

You can make C that operates like OO, but that will utlimately feel like an exercise in re-inventing the wheel..

JustJeff
Those can be pretty large applications, I know for example the Linux Kernel is written in C, but i'm essentially asking for information on techniques on how you structure a C program once you get over like 500 lines. I know alot of people seem to have misread the question and think I want to use OO in C, but I'm actually interested in ALL techniques that can be used to structure larger C Programs.
docflabby
Oh ok - well, a common approach is to try to divide the app into modules and then assign each module to a .c file, 'advertise' its merits in header (.h) files, and then use #includes to resolve source dependencies. Works pretty well up to a few KLOC. Where things usually go all pear shaped is when the dependencies get out of control, and .h files start including other .h files, or multiple source directories become necessary, or the ultimate horror, somebody starts putting variable declarations in .h files..
JustJeff
A: 

One minor thing is to order your .c files "backwards" - i.e. put main() at the bottom of the file, and always make sure local functions (ones that aren't in your .h file, that you just wrote for use in that file) live above where they're first used. This means you don't have to write prototypes for them, which is one less thing to fiddle with if you have to change their API.

Then, as a bonus, the 'gD' command in vim will always go to the definition of a function, if it's in the same file :)

C Pirate
Apart from having to keep the prototype and body in sync, a nice block of prototypes at the head of a .c file is a handy bit of documentation for the contents.
ConcernedOfTunbridgeWells