[c] How do you implement a class in C?

Assuming I have to use C (no C++ or object oriented compilers) and I don't have dynamic memory allocation, what are some techniques I can use to implement a class, or a good approximation of a class? Is it always a good idea to isolate the "class" to a separate file? Assume that we can preallocate the memory by assuming a fixed number of instances, or even defining the reference to each object as a constant before compile time. Feel free to make assumptions about which OOP concept I will need to implement (it will vary) and suggest the best method for each.

Restrictions:

  • I have to use C and not an OOP because I'm writing code for an embedded system, and the compiler and preexisting code base is in C.
  • There is no dynamic memory allocation because we don't have enough memory to reasonably assume we won't run out if we start dynamically allocating it.
  • The compilers we work with have no problems with function pointers

This question is related to c class oop embedded

The answer is


GTK is built entirely on C and it uses many OOP concepts. I have read through the source code of GTK and it is pretty impressive, and definitely easier to read. The basic concept is that each "class" is simply a struct, and associated static functions. The static functions all accept the "instance" struct as a parameter, do whatever then need, and return results if necessary. For Example, you may have a function "GetPosition(CircleStruct obj)". The function would simply dig through the struct, extract the position numbers, probably build a new PositionStruct object, stick the x and y in the new PositionStruct, and return it. GTK even implements inheritance this way by embedding structs inside structs. pretty clever.


My approach would be to move the struct and all primarily-associated functions to a separate source file(s) so that it can be used "portably".

Depending on your compiler, you might be able to include functions into the struct, but that's a very compiler-specific extension, and has nothing to do with the last version of the standard I routinely used :)


you can take a look at GOBject. it's an OS library that give you a verbose way to do an object.

http://library.gnome.org/devel/gobject/stable/


Do you want virtual methods?

If not then you just define a set of function pointers in the struct itself. If you assign all the function pointers to standard C functions then you will be able to call functions from C in very similar syntax to how you would under C++.

If you want to have virtual methods it gets more complicated. Basically you will need to implement your own VTable to each struct and assign function pointers to the VTable depending on which function is called. You would then need a set of function pointers in the struct itself that in turn call the function pointer in the VTable. This is, essentially, what C++ does.

TBH though ... if you want the latter then you are probably better off just finding a C++ compiler you can use and re-compiling the project. I have never understood the obsession with C++ not being usable in embedded. I've used it many a time and it works is fast and doesn't have memory problems. Sure you have to be a bit more careful about what you do but its really not that complicated.


I had to do it once too for a homework. I followed this approach:

  1. Define your data members in a struct.
  2. Define your function members that take a pointer to your struct as first argument.
  3. Do these in one header & one c. Header for struct definition & function declarations, c for implementations.

A simple example would be this:

/// Queue.h
struct Queue
{
    /// members
}
typedef struct Queue Queue;

void push(Queue* q, int element);
void pop(Queue* q);
// etc.
/// 

The first c++ compiler actually was a preprocessor which translated the C++ code into C.

So it's very possible to have classes in C. You might try and dig up an old C++ preprocessor and see what kind of solutions it creates.


My strategy is:

  • Define all code for the class in a separate file
  • Define all interfaces for the class in a separate header file
  • All member functions take a "ClassHandle" which stands in for the instance name (instead of o.foo(), call foo(oHandle)
  • The constructor is replaced with a function void ClassInit(ClassHandle h, int x, int y,...) OR ClassHandle ClassInit(int x, int y,...) depending on the memory allocation strategy
  • All member variables are store as a member of a static struct in the class file, encapsulating it in the file, preventing outside files from accessing it
  • The objects are stored in an array of the static struct above, with predefined handles (visible in the interface) or a fixed limit of objects that can be instantiated
  • If useful, the class can contain public functions that will loop through the array and call the functions of all the instantiated objects (RunAll() calls each Run(oHandle)
  • A Deinit(ClassHandle h) function frees the allocated memory (array index) in the dynamic allocation strategy

Does anyone see any problems, holes, potential pitfalls or hidden benefits/drawbacks to either variation of this approach? If I am reinventing a design method (and I assume I must be), can you point me to the name of it?


C isn't an OOP language, as your rightly point out, so there's no built-in way to write a true class. You're best bet is to look at structs, and function pointers, these will let you build an approximation of a class. However, as C is procedural you might want to consider writing more C-like code (i.e. without trying to use classes).

Also, if you can use C, you can probally use C++ and get classes.


I will give a simple example of how OOP should be done in C. I realise this thead is from 2009 but would like to add this anyway.

/// Object.h
typedef struct Object {
    uuid_t uuid;
} Object;

int Object_init(Object *self);
uuid_t Object_get_uuid(Object *self);
int Object_clean(Object *self);

/// Person.h
typedef struct Person {
    Object obj;
    char *name;
} Person;

int Person_init(Person *self, char *name);
int Person_greet(Person *self);
int Person_clean(Person *self);

/// Object.c
#include "object.h"

int Object_init(Object *self)
{
    self->uuid = uuid_new();

    return 0;
}
uuid_t Object_get_uuid(Object *self)
{ // Don't actually create getters in C...
    return self->uuid;
}
int Object_clean(Object *self)
{
    uuid_free(self->uuid);

    return 0;
}

/// Person.c
#include "person.h"

int Person_init(Person *self, char *name)
{
    Object_init(&self->obj); // Or just Object_init(&self);
    self->name = strdup(name);

    return 0;
}
int Person_greet(Person *self)
{
    printf("Hello, %s", self->name);

    return 0;
}
int Person_clean(Person *self)
{
    free(self->name);
    Object_clean(self);

    return 0;
}

/// main.c
int main(void)
{
    Person p;

    Person_init(&p, "John");
    Person_greet(&p);
    Object_get_uuid(&p); // Inherited function
    Person_clean(&p);

    return 0;
}

The basic concept involves placing the 'inherited class' at the top of the struct. This way, accessing the first 4 bytes in the struct also accesses the first 4 bytes in the 'inherited class' (Asuming non-crazy optimalisations). Now, when the pointer of the struct is cast to the 'inherited class', the 'inherited class' can access the 'inherited values' in the same way it would access it's members normally.

This and some naming conventions for constructors, destructors, allocation and deallocarion functions (I recommend init, clean, new, free) will get you a long way.

As for Virtual functions, use function pointers in the struct, possibly with Class_func(...); wrapper too. As for (simple) templates, add a size_t parameter to determine size, require a void* pointer, or require a 'class' type with just the functionality you care about. (e.g. int GetUUID(Object *self); GetUUID(&p);)


If you only want one class, use an array of structs as the "objects" data and pass pointers to them to the "member" functions. You can use typedef struct _whatever Whatever before declaring struct _whatever to hide the implementation from client code. There's no difference between such an "object" and the C standard library FILE object.

If you want more than one class with inheritance and virtual functions, then it's common to have pointers to the functions as members of the struct, or a shared pointer to a table of virtual functions. The GObject library uses both this and the typedef trick, and is widely used.

There's also a book on techniques for this available online - Object Oriented Programming with ANSI C.


In your case the good approximation of the class could be the an ADT. But still it won't be the same.


C Interfaces and Implementations: Techniques for Creating Reusable Software, David R. Hanson

http://www.informit.com/store/product.aspx?isbn=0201498413

This book does an excellent job of covering your question. It's in the Addison Wesley Professional Computing series.

The basic paradigm is something like this:

/* for data structure foo */

FOO *myfoo;
myfoo = foo_create(...);
foo_something(myfoo, ...);
myfoo = foo_append(myfoo, ...);
foo_delete(myfoo);

Also see this answer and this one

It is possible. It always seems like a good idea at the time but afterwards it becomes a maintenance nightmare. Your code become littered with pieces of code tying everything together. A new programmer will have lots of problems reading and understanding the code if you use function pointers since it will not be obvious what functions is called.

Data hiding with get/set functions is easy to implement in C but stop there. I have seen multiple attempts at this in the embedded environment and in the end it is always a maintenance problem.

Since you all ready have maintenance issues I would steer clear.


#include <stdio.h>
#include <math.h>
#include <string.h>
#include <uchar.h>

/**
 * Define Shape class
 */
typedef struct Shape Shape;
struct Shape {
    /**
     * Variables header...
     */
    double width, height;

    /**
     * Functions header...
     */
    double (*area)(Shape *shape);
};

/**
 * Functions
 */
double calc(Shape *shape) {
        return shape->width * shape->height;
}

/**
 * Constructor
 */
Shape _Shape() {
    Shape s;

    s.width = 1;
    s.height = 1;

    s.area = calc;

    return s;
}

/********************************************/

int main() {
    Shape s1 = _Shape();
    s1.width = 5.35;
    s1.height = 12.5462;

    printf("Hello World\n\n");

    printf("User.width = %f\n", s1.width);
    printf("User.height = %f\n", s1.height);
    printf("User.area = %f\n\n", s1.area(&s1));

    printf("Made with \xe2\x99\xa5 \n");

    return 0;
};

Use a struct to simulate the data members of a class. In terms of method scope you can simulate private methods by placing the private function prototypes in the .c file and the public functions in the .h file.


Examples related to c

conflicting types for 'outchar' Can't compile C program on a Mac after upgrade to Mojave Program to find largest and second largest number in array Prime numbers between 1 to 100 in C Programming Language In c, in bool, true == 1 and false == 0? How I can print to stderr in C? Visual Studio Code includePath "error: assignment to expression with array type error" when I assign a struct field (C) Compiling an application for use in highly radioactive environments How can you print multiple variables inside a string using printf?

Examples related to class

String method cannot be found in a main class method Class constructor type in typescript? ReactJS - Call One Component Method From Another Component How do I declare a model class in my Angular 2 component using TypeScript? When to use Interface and Model in TypeScript / Angular Swift Error: Editor placeholder in source file Declaring static constants in ES6 classes? Creating a static class with no instances In R, dealing with Error: ggplot2 doesn't know how to deal with data of class numeric Static vs class functions/variables in Swift classes?

Examples related to oop

How to implement a simple scenario the OO way When to use 'raise NotImplementedError'? PHP: cannot declare class because the name is already in use Python class input argument Call an overridden method from super class in typescript Typescript: How to extend two classes? What's the difference between abstraction and encapsulation? An object reference is required to access a non-static member Java Multiple Inheritance Why not inherit from List<T>?

Examples related to embedded

Compiling an application for use in highly radioactive environments Sorting 1 million 8-decimal-digit numbers with 1 MB of RAM What does this GCC error "... relocation truncated to fit..." mean? How do you implement a class in C? Understanding Linux /proc/id/maps Using floats with sprintf() in embedded C What is the difference between C and embedded C? Unit Testing C Code