How to structure your c program?

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?

9 c
13.10.2009 15:58:44
I would be tempted to use C++, but you can still write OO code in C - just without any language constructs.
Draemon 13.10.2009 16:04:52
The code needs to be in C, but if not i would surely agree ;).
Bernt 13.10.2009 16:08:56
Why does the code "need" to be in C? Is someone holding a gun to your head saying "If I see a single std::cout I'm gonna..."
Chris Lutz 13.10.2009 16:17:01
7 ОТВЕТОВ
РЕШЕНИЕ

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.
7
13.10.2009 16:11:51
You should clarify - by "unix file handle api" do you mean open(2) and friends or fopen(3) and friends?
Chris Lutz 13.10.2009 16:16:20
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 13.10.2009 16:30:48
Addendum: in most cases, you'll want a pointer, to avoid keeping global state.
Michiel Buddingh 13.10.2009 16:34:31

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.

2
13.10.2009 16:12:04
0
13.10.2009 16:13:39

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).

1
23.05.2017 12:19:37

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.

2
13.10.2009 16:18:53

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));
}
-1
13.10.2009 16:44:42

A few suggestions...

• Make use of the static modifier as much as you can; it's (mostly) the equivalent of private in OO languages.

• Try not to use too many global variables, especially if your program uses multiple threads.

• Group related info together into structs; these are your objects in C.

• C doesn't have exception handling, so check the return values of all the system functions you call.

0
13.10.2009 20:42:43