0

I need to do a large Project in C and C only, without external librairies (except for SDL). I started looking for ways to do some kind of class in C, what led me to that :

typedef void (*voidFunction)(void);

typedef struct{
    int id;                             
    voidFunction printId;
} Object;

Object *new_Object(int id){
    Object *newObject = malloc(sizeof(Object));
    newObject->id = id;
    void printId(){
        static Object *this = NULL;
        if(!this) this = newObject;
        printf("%d\n", this->id);
    };
    newObject->printId = printId;
    return newObject;
}

int main(){
    Object *object = new_Object(5);
    object->printId();
    object->id++;
    object->printId();
    return 0;
}

Output of main :

5
6

So this works, but does it seems reasonable ? Should I expect a backlash if I use this kind of architecture for a big project? Maybe I'm typing out of my allocated memory without realizing it?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
TerraS77
  • 13
  • 1
  • 4
    What *benefit* is this getting you? Classes provide a lot of features, and all this gets you is a pretty limited means of method invocation. Reinventing classes in C is ugly and kinda terrible to write/read, so the question to ask first is: "What are my pseudoclasses getting me? Is it worth the ugliness?" – ShadowRanger Jan 15 '22 at 15:40
  • Well, for example I will have a large list of similar objects in term of properties, but with really different means of display. This would make me able to just call a object->render() on each of the objects in a chained list. Since I will have really few classes, but will use and call them a lot, I can spare a bit of ugliness for the abstraction I get. My question is really : Is this future segfault material ? – TerraS77 Jan 15 '22 at 15:50
  • Defining a nested function inside `new_Object` only works due to an extension provided by your compiler. That is not standard C. – Gerhardh Jan 15 '22 at 16:26

3 Answers3

5

Techniques for implementing polymorphism in C are long established, check this answer for instance https://stackoverflow.com/a/351745/4433969

Your implementation seems to be broken. Nested functions are non-standard extension. I also have doubts about static this variable.

Nick Zavaritsky
  • 1,429
  • 8
  • 19
1

The non-standard nested function printId is used incorrectly. In GCC documentation Nested functions one can read:

If you try to call the nested function through its address after the containing function exits, all hell breaks loose.

The nested functions are called via trampolines, the small pieces of executable code located on stack. This code is invalidated when the parent function exits.

Though as the functions does not refer to any local variables the code will likely work. The compiler will likely avoid trampolines but rather create a kind-of "anonymous" static function.

The idiomatic solution should take a pointer to "Object" as an argument rather than use a static variable.

typedef struct Object {
    int id;                             
    void (*printId)(struct Object*);
} Object;

void printId(Object *this){
        printf("%d\n", this->id);
};

...

object->printId(object);
tstanisl
  • 13,520
  • 2
  • 25
  • 40
0

There are advantages for using a struct to organize data for bulk processing. However, the only advantage of using the function pointer rather than calling the function directly would be:

  1. To allow the function pointer to point to different functions having the same type for different instances of the object.
  2. To hide the "member" function definition from the linker. For example, the function printId could be declared as static within the module containing the definition for "constructor" new_Object.
Jonathon S.
  • 1,928
  • 1
  • 12
  • 18