tags:

views:

223

answers:

7

I've been working/coding in C#/Java for some years, so the basics etc. don't give me to much a hard time. But I've never done anything larger than small commandline learning programs in c.

Now I'm trying to make a mobile phone emulator for Linux and I have no clue how to structure my code when its not object oriented. I have 3 big books that cover c in detail but none of them cover how to code for maintainability in a bigger project.

So i was hoping some of you more experienced people could point me to a best practice or similar?

+5  A: 

Some thoughts (and this question should be a community wiki)

  • Even if it's not fully-fledged object-oriented programming, try to stick to information hiding practices. Let your functions return pointers or handles to opaque structures (the unix file handle api is a good (early) example. Use static functions where you'd otherwise use private methods.
  • Try to keep related functionality contained to a single file. This will make it easier to use the abovementioned static keyword, as well as give you a good indication when it's time to split off some functionality into a seperate file. For a Java programmer, this shouldn't be too strange a practice.
  • The standard practices on commenting apply. Use something like Doxygen if you're looking for something similar to javadoc/C# XML comments.
  • If you really haven't done anything serious in C for a while, coming to grips with practices for keeping your memory management clean and sensible, even though it's not hard per se, is going to hurt a lot more then establishing practices for maintainability. Just a warning.
Michiel Buddingh'
You should clarify - by "unix file handle api" do you mean `open(2)` and friends or `fopen(3)` and friends?
Chris Lutz
I meant the `open(2)` calls--`fopen(3)` is actually part of the C standard. For the purpose of argument, it's irrelevant, though, as both use similar information hiding practices. Whether a file handle is a pointer or an integer is an implementation detail.
Michiel Buddingh'
Addendum: in most cases, you'll want a pointer, to avoid keeping global state.
Michiel Buddingh'
+1  A: 

structure it generally the same way. Separate things into several files, each containing code which do related work.

Often with C, you can still think about objects. But instead of classes with methods, they are structures and functions which operate on a struct.

Evan Teran
A: 

You can do OO in c see for example:

Nifle
+1  A: 

Just because it's C doesn't mean it's not object oriented. See this question or any number of questions named with some variation of "Learning C coming from Object Oriented background."

Techniques like this are still used today - GIMP is built on GTK+, which includes the GObject library for object-oriented coding in C. It may not be the best way, and may not be "idiomatic" C, but it may help you.

The other advice I have on how to code maintainability in a large project is use libraries. C doesn't have a lot built in, so the more functionality you can squeeze out of a portable (open source?) third party library, the less code you have to write (and therefore maintain).

GTK+ once again has GLib, which is a catch-all library with lots of features that people found themselves implementing and reimplementing in C. Apache has its own, the Apache Portable Runtime, which does something very similar (but with different kinds of functions). There are also a few string libraries, which will probably save you a lot of headache, and some more special purpose libraries (Readline for interactive prompts, Ncurses for textual interfaces like vi, etc) that are useful but may not play a huge role in your particular application.

The best choices depend to some degree on what you're writing. If you're writing an operating system kernel or a device driver, or any application for embedded systems, disregard all of the above advice. If you're looking to implement a programming language, look into flex and bison to get started with grammars on a few smaller test projects, but I recommend rolling your own parser and lexer for a serious project (if for no other reason than the improved error reporting).

Chris Lutz
A: 

I'd recommend splitting your project into smaller components, and place each component in its own .c and .h file. You place the code in the .c file and the structures and prototypes in the .h file.

Doing this, you can program object-oriented in C if you keep your functions reentrant: Say a couple of functions perform a function FOO, then rather than having global variables in foo.c, declare a structure named FOO in foo.h and have the functions take a pointer to a FOO structure as their first parameter.

If a function fred() is only used somewhere in foo.c, mark it static and don't put the prototype in foo.h

Also, search Google codesearch for C projects to see how it is done.

iWerner
A: 

OO is just syntactic sugar. The original C++ compilers compiled to C. Here's a basic example of roughly the same class in Java and in C:

Point.java
import java.lang.Math;

public class Point
{
    private int x, y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int getDistance(Point p)
    {
        return Math.sqrt((p.x - this.x) * (p.x - this.x) + (p.y - this.y) * (p.y - this.y));
    }
}

Point.h
typedef struct __Point Point;
typedef struct __Point
{
    int x, y;
    int (*getDistance)(Point*,Point*);
} Point;

Point* new_Point(int, int);
void delete_Point(Point*);
int getDistance(Point*, Point*);

Point.c
#include <math.h>
#include "Point.h"

Point* new_Point(int x, int y)
{
   Point* this = malloc(sizeof(Point));
   this->x = x;
   this->y = y;
   this->getDistance = getDistance;
}

void delete_Point(Point* this)
{
    free(this);
}

int getDistance(Point* this, Point* p)
{
    return sqrt((p->x - this->x) * (p->x - this->x) + (p->y - this->y) * (p->y - this->y));
}
Imagist
A: 
Loadmaster