tags:

views:

98

answers:

6

Are there any tips which we should follow for good design when we are considering the 'C' as the implementation language.

I want tips which should be considered because we are using 'C' as the implementation language and not related to the functionality.

A: 

You mention C only, but is ObjectiveC at all an option for you?

Chris O
This is a comment, and not a very helpful one at that.
Chris Lutz
+1  A: 

C Interfaces and Implementations is a great book on the subject

qrdl
+1  A: 

You might take some info from the list.h header in the Linux kernel. It implements a few support functions and macros for a generic list type that looks like this:

struct list {
  struct list *prev, *next;
};

This holds no data, because if we want to make a list of ints, we simply say:

struct intlist {
  struct list list;
  int data;
};

Because a struct pointer can safely be casted to the type of it's first element, a struct intlist* can now be passed to all the macros and functions in list.h that expect a struct list*. The macros and functions in list.h only manipulate the list structure, and can just as safely be used on a struct intlist*. The same functions and macros would work just as well with a struct strlist* or a struct stufflist*.

In fact, the Linux kernel list.h uses some evil trickery to allow you to place the struct list field anywhere in your linked list structure you like, but some of that may not be portable beyond GCC. For consistency, readability, and other stuff, I would always put it at the beginning. I can't really think of a good reason to have it at the end.

Some people may consider this a hack. I consider it a well-thought-out lightweight generic list implementation.

Chris Lutz
Re: evil trickery, I assume you're referring to the `containerof` macro? it relies on `offsetof`, which is portable
Hasturkun
I had thought that `offsetof` was C99 (and therefore slightly less portable as some compilers don't implement C99 features) but I can't find any reference for that, so I don't know if it was present in C89 or not (I think it is, as I'm finding C++ references about it). Anyway, the version of `list.h` I have doesn't use `containerof` or `offsetof` but uses a custom version of `offsetof`. If I were using this in code (especially non-kernel code with no binary formatting requirements) I would require all lists have the linked list struct at the beginning for reasons already mentioned.
Chris Lutz
Hasturkun
A: 

please refer to unix or linux driver codes...

wrapperm
I agree that Unix or Linux Driver Codes will have a very good design. But, aren't these designs standardized for reference somewhere?
Jay
They are standardized and are 100% reliable... thats why you are finding the reference there...
wrapperm
A: 

Rather than discuss general design considerations, which I assume you're familiar with, here are two things that are relatively specific to C:

  • Hide the details of data structures by returning pointers to opaque structures to the client code. This is done by having

    typedef struct whatever Whatever;

    in the header-file for a module and only defining the data structure in the module itself:

    struct whatever {
           ...
    }
  • Because memory management is crucial to C and, in particular, allocated memory must be freed, adopt a coding style that ensures this. For example

    int error = 0;
    Whatever* ptr = (Whatever*)malloc(sizeof(Whatever));
    if (NULL == ptr) {
        error = 1;
        ...
    }
    else {
        ...
        if (error)
            free(ptr);
    }                    /* "ptr" allocated */
    

or

    Whatever* ptr = (Whatever*)malloc(sizeof(Whatever));
    if (NULL == ptr)
        goto NULL_PTR;
    ...
    if (error)
        goto UNWIND_PTR;
    ...
    return 0;
    UNWIND_PTR:
        free(ptr);
    NULL_PTR:
        return -1;
Steve Emmerson