Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Object Orientated C

Object Orientated C
This is an odd one.

Reason for doing this
The main requirement of what I am doing at my job is that I keep the project multi-platform with minimal effort for integration, the reason is that we've been "porting" apps from iOS to Android by simply rewriting with Android in mind, this has the benefit of good usage of the Android tools and practises (We can thus make it perform better on Android or add in Android specific features).

The project I'm working on already uses an API that both iOS and Android share, so there's no need for platform specific benefits, I just need to keep it multiplatform.

Objective C, iOS's recommended programming language, is described as a "strict superset of C", meaning that it can run C code perfectly with a simple copy-paste or through using the #include preprocessor (This essentially copy-pastes in the code at compile-time).
Android's SDK is all Java but provides the NDK, a way of hooking on libraries native to the device (In my case, ARM processors), so I can compile C/C++ code into a library that Android's Java side connects with.

Here's the problem, the nature of this project is VERY object-orientated, however C is NOT an object-orientated programming language.
I cannot use C++ as the steps for linking C++ into iOS is more complicated than simple, light C #includes, not to mention that C++ is a bit of a mess to program with (Sorry C++, you're my favourite language, but it's true). At least C++'s syntax isn't all crazy like in objective-C :smile:.

So part of the project is re-creating C++ in C (C++ started off as a preprocessor to produce OOP C code, these days C++ is rather different to C, it is not a strict superset at all).

The technique I use is exploiting the C structures to act as my classes.

Why NOT to do this - Read this if you're considering C!
I do NOT recommend doing this at all unless you absolutely need to use C, for example the Sony PSP (And I think the DS) only has a C compiler so programming in C is pretty much the only option.
Why pretend to use C++ when you can actually use C++? There is no benefit beyond the rare circumstances such as my one.

Extra benefits
Before I even started this we did some performance tests in the office against iOS's Objective-C. Calling one of these C classes' functions versus calling an Objective-C method we've seen as much as twice the performance speed in nanoseconds (Tested using mach timer), this was not scientifically tested and will certainly not be true in some circumstances, so don't start throwing away Objective-C code just because I wrote this! There is no reason to write an application you're not planning to port in C just for performance benefits.
The reason for this speed-up is most likely due to Objective C's messaging system and garbage collector (Yes it does have a garbage collector, I've had battles against this thing for it's "smart" memory resizing during one of it's clean-up duties. iOS devices do not feature the garbage collector, so it's only a problem for desktop applications and the iOS simulator, which is essentially a desktop application anyway).

For legal reasons I cannot include any code I've written at work, but I'll show the methods behind adding OOP into C as it's already documented online.

Topic 1: Basic Classes
In C++ a class looks like this:
C++:
class xiMyClass {

    // Class members are default Private visibility

public:

    int     id;

    char *  name;

    void    Function( const int argument );

};
Using C structures, we can somewhat emulate this:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct xiMyClass_s {

    /* Class members can only be public! */

    <span style="color: #993333;">int     id;

    <span style="color: #993333;">char *  name;

    <span style="color: #993333;">void    ( * <span style="color: #000000; font-weight: bold;">Function )( <span style="color: #993333;">struct xiMyClass_s * <span style="color: #993333;">const, <span style="color: #993333;">const <span style="color: #993333;">int ); /* Function pointer */

} xiMyClass_t;

 

xiMyClass_t * NewMyClass();
Things to note:
  • The C function pointer, if it's a self-modifying function, must include a pointer to it's calling instance, this is the big drawback that exposes how hacky this really is!
  • The argument names in the C structure's function pointer are optional.
  • We need to define the "new" keyword for the C structure, this is unique to every class type so we call it NewMyClass (In C++ the call would be "new xiMyClass", so I name the C function to mimic this ordering).

The implementation of this particular class in C++ can be something like this:
C++:
void xiMyClass::Function( const int argument ) {

    id = argument;

}
However, in C we need to manually build the structure with our NewMyClass function, in C++ the new keyword does this for us so we need to define it ourselves.
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void MyClassFunction( xiMyClass_t * <span style="color: #993333;">const this, <span style="color: #993333;">const <span style="color: #993333;">int argument ) {

    this->id = argument; /* This is why we need to parse the calling instance */

}

 

/* Define the "new" keyword for this class */

xiMyClass_t * NewMyClass() {

    xiMyClass_t * <span style="color: #993333;">const new = ( xiMyClass_t * )malloc( <span style="color: #993333;">sizeof( xiMyClass_t ) );

 

    /* Assign function pointer */

    new->Function = &MyClassFunction;

 

    <span style="color: #b1b100;">return new;

}
Things to note:
  • The NewMyClass is used to assign the function pointers, this is critical for this to work.
  • NewMyClass() can also be written as a constructor, so some parameters can be thrown in to create the instance and even some function calls used after the pointers are assigned.
  • Not only does the "new" keyword need to be defined in C, the "delete" can also be defined if simply using free() on the instance is not enough. Using DeleteMyClass() as a custom deconstructor means you can clean your memory and perform additional operations.

To use this class, C++ we have
C++:
xiMyClass * const classInstance = <span style="color: #0000dd;">new xiMyClass(); // Will use a C++ default constructor

classInstance->Function( <span style="color: #0000dd;">6 ); // Call function

classInstance->id; // This should equal 6

<span style="color: #0000dd;">delete( classInstance );
And in C
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol>xiMyClass_t * <span style="color: #993333;">const classInstance = NewMyClass(); /* Uses our custom New as the default constructor */

classInstance->Function( classInstance, <span style="color: #cc66cc;">6 ); /* When calling we must also parse the instance of the class */

classInstance->id; /* This should equal 6 */

free( classInstance );

Additional Info
You'll probably begin to see how C++ works when it is translated into C.
I have actually ported some C++ libraries to C using this method. Some features of C++ are harder to mimic than others, particularly template types, C has the benefit of the void pointer which can somewhat act as template types, but there are limits.

Here's the big lesson, the more you program in C the more you see how messy C++ is. C++ is my favourite language and it's my weapon of choice for any kind of programming challenge, however after writing in C for so long at work I can definitely say that C++ is quite broken in some aspects, particularly STL and argument overrides, personally I prefer FunctionWithInt( int num ), FunctionWithFloat( float num ) to Function( int num ), Function( float num ), how do you know which one will be used and what if the compiler chooses to cast the int to a float or vice-versa? Operator overloading is another complaint of mine, while I think the feature is great, it's been very badly abused, especially with<<the<<stl<<string<<stream!

Next Topic: Class Inheritance in C
 
Nice.
Even though I don't have a particular use for it.
I didn't even read it all, because I don't know either language.
I still want to learn C++, but I'm doing weblanguages first.

Still nice.
 
If you want to learn C/C++ I can write some lessons up for everyone, I suggest you learn bad C++ before moving onto real C++ and then C, bad C++ practices will teach you C in a simpler environment while preparing you for C++ without scaring you with classes and inheritance.

Class Inheritance in C

The rest of this post is very hacky and somewhat ridiculous to read, but it is crucial for an object-orientated C approach.

In C++ inheritance is pretty simple:
C++:
class xiShape {

public:

    int colour;

};

 

class xiSquare: public xiShape {

public:

    float   size;

};

So now an instance of xiSquare can access colours as such:
C++:
xiSquare * square = <span style="color: #0000dd;">new xiSquare(); // Will automatically call xiShape's constructor

square->size = <span style="color: #0000dd;">1.0f;

square->colour = 0xFF0000; // Access colour

The C version of this is a bit crazy.
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct shape_t {

    <span style="color: #993333;">int colour;

} xiShape_t;

 

xiShape_t * NewShape();

 

<span style="color: #993333;">typedef <span style="color: #993333;">struct square_t {

    xiShape_t * base; /* The class retains a pointer to it's parent */

 

    <span style="color: #993333;">float   size;

} xiSquare_t;

 

xiSquare_t * NewSquare( xiShape_t * <span style="color: #993333;">const base );

The implementation of NewSquare() assigns the base variable to the inheriting class.

The usage would look something like this:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol>xiSquare_t * square = NewSquare( NewShape() ); /* Parse an instance of the inheriting class */

square->size = <span style="color: #cc66cc;">1.0f;

square->base->colour = 0xFF0000; /* Access colour through the parent class */
I know this looks very cheaty, but it's practically what C++ is doing underneath.

Things to note:
  • Any multi-inheritance would simply be an array of pointers to the inheriting classes.

Accessing Through Classes

If I had a list of xiShapes that all have the base class of xiSquare, in both C-with-classes and C++ I need to cast to my target class if I want to grab all the squares.

The scenario is, we have a list of shapes, we don't need to know if they are squares, circles or triangles, we just want to run through this list and get the size of any squares in the list.

C++
C++:
for ( int ii = <span style="color: #0000dd;">0; ii < LIST_SIZE; ii++ ) {

    xiShape * shape = shapes[ii];

    // A test to see if this is a square needs to be made, the best, non-hacky way is to record a list of class type enums

    // continue; // Do this if it is not a square

    xiSquare * square = dynamic_cast<const xiSquare *>( shape );

    square->size; // Access the size of square

}
C Equivalent
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #b1b100;">for ( <span style="color: #993333;">int ii = <span style="color: #cc66cc;">0; ii < LIST_SIZE; ii++ ) {

    xiShape_t * shape = shapes[ii];

    /* A test to see if this is a square needs to be made, the best, non-hacky way is to record a list of class type enums */

    /* continue; */ /* Do this if it is not a square */

    xiSquare_t * square = ( xiSquare_t * )shape->inherit;

    square->size; /* Access the size of square */

}
The big difference in this is that we grab the square's class through it's base class with the inherit.
inherit is a void pointer ( void * ), a pointer to any kind of data, so inside the class xiShape_t is the member void * inherit, which is set to 0 in the NewShape() constructor.

The key piece of this is during the NewSquare() constructor, inside that we have parsed the parent class as a pointer which we assign base. We can actually access this class during the construction, so we can use this line inside the construction:
new->base->inherit = ( void * )new;

This is where mutation can be done, not only can we assign a variable in the base class that points back to the derived class, we can also override some of the base class's functions:
new->base->Update = &SquareUpdate(); /* Square update is implemented within the Square class' C file */

That last part is something that I use at work, without that ability the entire project would not be able to move forward, we can set up an update loop that runs code of any class without having to cast between classes:
shape->Update( shape ); /* Because we changed this pointer to SquareUpdate(), SquareUpdate() is in stead called */

And to get a handle on the square itself within SquareUpdate() we can now do this:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void SquareUpdate( xiShape_t * <span style="color: #993333;">const base ) {

    xiSquare_t * <span style="color: #993333;">const this = ( xiSquare_t * )base->inherit;

    this->size = <span style="color: #cc66cc;">2.0f;

    base->colour = 0x00FF00; /* We can alternatively use this->base->colour */

}
Things to note:
  • Inheritance is a lot easier in C++ compared to the C-with-classes method of inheritance, see my reasons for not doing this in the first post.

Next Topic: Fake member visibility in C
 
Nice write up. Like you said, writing in lower level languages gives you a ton of control and often highlights shortcomings of using a more abstract language. The stuff C++ gives you out of the box is very nice, but if you want more control and (perhaps) better performance, recreating it in C might be the way to go. I think this is why Jonathan Blow advocates building your own engine rather than using something like flash punk, or unity. Still, IMO, the "best" approach is the one that results in actually making a game which varies wildly.
 
Making your own engine is always going to be better than using an out of the box engine if you can program, but I'd never recommend programming a game in C when C++ fits the job more.

The control gained when writing in straight C is incredible, makes C++ feel like Java, however the only performance gained is where C doesn't use the C++ STL, C++'s standard libs on some systems are much slower than straight C, qsort() comes to mind, but if you're not using STL then the performance is about the same, especially when some compilers actually compile C++ to the equivalent ASM as C with classes.

The one problem with C's STD is that it's just as slow as C++'s equivalent STL on Windows as Microsoft decided to ship C++ code inside their C libraries.

As for games specifically, Allegro game library is C and I highly recommend it for C games.

Edit: every benefit and issue I described is explained in this website http://unthought.net/c++/c_vs_c++.html
Like me, the author champions C++, he even shows how the C++ STL is much slower than equivalent C STD usage, but highlights readability as the problem.

But there's always something pure and good about C programming, even when doing this crazy OOP C code you have glimpses of benefits and good code
 
Fake member visibility in C

Yet another crazy C tactic for doing something that you should probably use C++ for.

The common method for doing struct member visibility in C is as such:

HEADER
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct privateMembers_s privateMembers_t;

 

<span style="color: #993333;">typedef <span style="color: #993333;">struct myClass_s {

    privateMembers_t *  privateMembers;

 

    <span style="color: #993333;">int publicVariable;

    <span style="color: #993333;">int ( * PublicFunction )( <span style="color: #993333;">struct myClass_s * <span style="color: #993333;">const, <span style="color: #993333;">const <span style="color: #993333;">int, <span style="color: #993333;">const <span style="color: #993333;">int );

} xiMyClass_t;

 

xiMyClass_t * NewMyClass();

<span style="color: #993333;">void DeleteMyClass( xiMyClass_t * <span style="color: #993333;">const this );

 
IMPLEMENTATION
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol>/* We re-define the typedef of the privateMember struct */

<span style="color: #993333;">typedef <span style="color: #993333;">struct privateMembers_s {

    <span style="color: #993333;">int privateVariable;

    <span style="color: #993333;">int ( * PrivateFunction )( xiMyClass_t * <span style="color: #993333;">const, <span style="color: #993333;">const <span style="color: #993333;">int, <span style="color: #993333;">const <span style="color: #993333;">int );

} privateMembers_t;

 

xiMyClass_t * NewMyClass() {

    xiMyClass_t * <span style="color: #993333;">const new = malloc( <span style="color: #993333;">sizeof( xiMyClass_t ) );

    new->privateMembers = malloc( <span style="color: #993333;">sizeof( privateMembers_t ) ); /* We must allocate the memory of the private members */

 

    /* Continue normal construction */

 

    <span style="color: #b1b100;">return new;

}

 

<span style="color: #993333;">void DeleteMyClass( xiMyClass_t * <span style="color: #993333;">const this ) {

    free( this->privateMembers );

    free( this );

}

 

The benefit of this one is that all the variables and functions inside the private members are only visible to the implementation file, which is exactly what we wanted.
The draw-back is that the private members are no longer defined along with the header file, we need to swap between header and implementation when defining the class.

I like to keep everything together, I also like to respect the original nature of C, which is to not have private visibility to begin with.
So what I do is essentially the following:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct myStructure_s {

    <span style="color: #993333;">struct privateVariables_s {

        <span style="color: #993333;">int x;

        <span style="color: #993333;">int y;

    } PRIVATE_STUFF_PLEASE_DONT_LOOK_INSIDE_THANKS;

 

    <span style="color: #993333;">int publicVariable;

} myStructure_t;
I know it seems silly, but the whole reason I started exploring the idea of putting private variables into C is not because I need to hide stuff, but because things were getting confusing.

At work I have the following function in a C class:
void SetFOV( xiClass_t * const this, const float newFieldOfView );

I also have this variable:
float fov;

During development I got a bit confused and started writing:
myClass->fov = 65.0f;
And I wondered why nothing happened.

The contents of SetFOV looks similar to this (For legal reasons I cannot show what it really looks like but here's the idea):
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void SetFOV( xiClass_t * <span style="color: #993333;">const this, <span style="color: #993333;">const <span style="color: #993333;">float newFieldOfView ) {

    this->fov = newFieldOfView;

    this->RebuildViewMatrix( this );

    this->manager->RebuildVisibilityTree( this->manager );

}
So when I was using myClass->fov = 65.0f and nothing was happening it was because it was not calling the functions that needed to be called to notify the system that the FOV has changed.
myClass->SetFOV( myClass, 65.0f ) would have called these functions and would have worked fine.

Okay so there's a real problem here, my variables and function names are a bit ambiguous and I was getting confused, one solution would be to just remember the problem, but I knew that when I needed to pass the code-base on or train someone else in using this code I'd have to go through all of these situations and inform them of the problem.

The easier method was to just flag the variables that should not be set by the user as private so then we're encouraged to use the function (Note the word encouraged).

So in the implementation file, in stead of writing:
this->PRIVATE_STUFF_PLEASE_DONT_LOOK_INSIDE_THANKS.x;
I used a macro to make things a bit easier:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #339933;">#define PRIVATE PRIVATE_STUFF_PLEASE_DONT_LOOK_INSIDE_THANKS

 

this->PRIVATE.<span style="color: #202020;">x;

Macros are a bit cheaty, but I use them wherever it makes things easier to read and easier to write.

At work I have macros setup so I can do this in the header file:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol> 

<span style="color: #993333;">typedef <span style="color: #993333;">struct myClass_s {

    xiBaseClass_t * base;

 

    PUBLIC(

        <span style="color: #993333;">int publicVariable;

        <span style="color: #993333;">void    ( * PublicFunction )( <span style="color: #993333;">struct myClass_s * <span style="color: #993333;">const );

        );

 

    PRIVATE(

        <span style="color: #993333;">int privateVariable;

        <span style="color: #993333;">void    ( * PrivateFunction )( <span style="color: #993333;">struct myClass_s * <span style="color: #993333;">const ); /* A normal implementation function would work just fine, making private functions pointless */

        );

} xiMyClass_t;

 

The PUBLIC() macro expands to empty, so it's there to keep things familiar with C++, the PRIVATE macro expands to generate a unique structure name for the private variables, I do this numerically so it generates struct private_#_s, with the hash being an incrementing number using my preprocessor's __COUNTER__ macro.

In C++ a similar class would be as such:
C++:
 

class xiMyClass {

public:

        int publicVariable;

        void    PublicFunction();

 

private:

        int privateVariable;

        void    PrivateFunction();

};

 
So you can see that I attempted to keep in line with my C++ experience on this one.

I am currently looking into expanding this so the MACRO produces unique names for the instance of the struct, that way we can't just define the PRIVATE variable to avoid the discouraging variable name where it shouldn't be seen.

So this is how I fake member visibility in C with classes, and it is faked because anyone can simply write out that discouraging name and then get access to the private members, but as I stated in my example above, this is probably the best way to go about it in C without having the split up the class implementation.

Next Topic: Default function arguments in C - (Yes this is possible! More macro hacks ahead...)
 
Default function arguments in C

Unlike C++, C does not support default arguments.
Here's a C++ function with a default argument
C++:
void MyFunction( const int variable = <span style="color: #0000dd;">4 ); // Forward declare with default argument

 

void MyFunction( const int variable ) {

    // If user calls this function with no argument, then we can expect variable to be 4

}
In C there would be a compile error at the forward declaration about the setting of the number 4, with LLVM on OSX it actually errors with "C does not support default arguments".
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void MyFunction( <span style="color: #993333;">const <span style="color: #993333;">int variable ) {

    /* We must set the argument variable when calling this function */

}

So we could turn around and shed a tear, or we could do more crazy macro stuff.

The method I use for pulling this off is default argument structures:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct myFunctionArgs_s {

    <span style="color: #993333;">const <span style="color: #993333;">int   variable; /* We actually store a const variable in the structure */

} myFunctionArgs_t;

 

<span style="color: #993333;">void MyFunction( <span style="color: #993333;">const myFunctionArgs_t args ) {

    <span style="color: #993333;">const <span style="color: #993333;">int variable = args.<span style="color: #202020;">variable ? args.<span style="color: #202020;">variable : <span style="color: #cc66cc;">4; /* This we where we default the number 4 */

}

So now we call the function as such:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol>MyFunction( ( myFunctionArgs_t ){} ); /* No argument, defaults to 4 */

MyFunction( ( myFunctionArgs_t ){ <span style="color: #cc66cc;">7 } ); /* Argument is 7 */
Quite a bit to add for default params! So now we use the macros:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct myFunctionArgs_s {

    <span style="color: #993333;">const <span style="color: #993333;">int   variable; /* We actually store a const variable in the structure */

} myFunctionArgs_t;

 

<span style="color: #993333;">void MyFunction( <span style="color: #993333;">const myFunctionArgs_t args ) {

    <span style="color: #993333;">const <span style="color: #993333;">int variable = args.<span style="color: #202020;">variable ? args.<span style="color: #202020;">variable : <span style="color: #cc66cc;">4; /* This we where we default the number 4 */

}

<span style="color: #339933;">#define MyFunction( ... ) MyFunction( ( myFunctionArgs_t ){ __VA_ARGS__ } )
Macros that take arguments (Some call them function macros) simply insert the arguments into the line, so in the case of #define FUNCTION_MACRO( X, Y ) ( X + Y ) the X + Y will be replaced with the X, Y from the macro arguments

Just like with varargs in C (Function arguments with infinite length, such as the printf() function) macros can also have the (...) arguments, as long as we expand it into __VA_ARGS__.

So what this macro does is it replaces any use of MyFunction() with the version that casts the arguments into the myFunctionArgs_t structure.

Now we can finally call MyFunction() and expect the default value to be 4.

Note: I usually name my macros in all capitals with underscores, for the sake of looking sane the default argument functions retain the camel-case with uppercase first letter convention.

The BIG draw-back!
As usual, there is a problem with this.
We use the inline conditional to check if the argument is there or not, const int variable = args.variable ? args.variable : 4;.
C checks against a certain value for cases where we are checking if things are there or not and in this case it checks against the value zero.
so the problem is essentially:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">int variable;

<span style="color: #b1b100;">if ( args.<span style="color: #202020;">variable != <span style="color: #cc66cc;">0 ) {

    variable = args.<span style="color: #202020;">variable;

} <span style="color: #b1b100;">else {

    variable = <span style="color: #cc66cc;">4;

}
It works, until we WANT the argument to be zero, then it's just going to throw us back to 4!

So the draw back is the default arguments will always cover the case of zero, a lot of the time your default value is zero so it won't matter, but for cases when it's not zero this will be a paint.

My (terrible) solution was to parse a macro TINY_NUM in the cases where I wanted zero and expect a float value of 0.00000001f, which is not a very friendly method as it means you need to inform everyone using the code of this problem.
The alternative is to probably use pointers as the arguments, so we check if the pointer is 0x00000000, which it shouldn't be if we set it. Using pointers like this doesn't always work and it means that all the arguments must be set to a variable before being parsed. Throwing pointers around like that is not the best thing to do.

Usually I'd give up at such drastic draw-backs. However, there is something that C gains here that C++ DOES NOT HAVE!
A really, REALLY cool feature that I've used so much in my C projects.

In C++ if we have multiple arguments we do this:
C++:
void MyFunction( const int valueA = <span style="color: #0000dd;">1, const int valueB = <span style="color: #0000dd;">2 ); // Forward declare

 

void MyFunction( const int valueA, const int valueB ) {

    // Do stuff with valueA and valueB

}
And here's the limitation of this:
C++:
MyFunction( <span style="color: #0000dd;">3, <span style="color: #0000dd;">4 ); // valueA == 3, valueB == 4

MyFunction( <span style="color: #0000dd;">5 ); // valueA == 5, valueB == 2

MyFunction(); // valueA == 1, valueB == 2

This C cheaty macro default argument method with structures system (CCMDAMWSS in short) totally beats C++ on this aspect.

Here's the first case:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct myFunctionArgs_s {

    <span style="color: #993333;">const <span style="color: #993333;">int   valueA;

    <span style="color: #993333;">const <span style="color: #993333;">int   valueB;

} myFunctionArgs_t;

 

<span style="color: #993333;">void MyFunction( <span style="color: #993333;">const myFunctionArgs_t args ) {

    <span style="color: #993333;">const <span style="color: #993333;">int valueA = args.<span style="color: #202020;">valueA ? args.<span style="color: #202020;">valueA : <span style="color: #cc66cc;">1;

    <span style="color: #993333;">const <span style="color: #993333;">int valueB = args.<span style="color: #202020;">valueB ? args.<span style="color: #202020;">valueB : <span style="color: #cc66cc;">2;

}

<span style="color: #339933;">#define MyFunction( ... ) MyFunction( ( myFunctionArgs_t ){ __VA_ARGS__ } )

 

MyFunction( <span style="color: #cc66cc;">3, <span style="color: #cc66cc;">4 ); /* valueA == 3, valueB == 4 */

MyFunction( <span style="color: #cc66cc;">5 ); /* valueA == 5, valueB == 2 */

MyFunction(); /* valueA == 1, valueB == 2 */

/* My fellow C++ fans, prepare to have your mind blown */

MyFunction( .<span style="color: #202020;">valueB = <span style="color: #cc66cc;">6 ); /* valueA == 1, valueB == 6 */

This also has an amazing method of pointing around the structure as you build it:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">typedef <span style="color: #993333;">struct myFunctionArgs_s {

    <span style="color: #993333;">const <span style="color: #993333;">int   valueA;

    <span style="color: #993333;">const <span style="color: #993333;">int   valueB;

    <span style="color: #993333;">const <span style="color: #993333;">int   valueC;

} myFunctionArgs_t;

 

<span style="color: #993333;">void MyFunction( <span style="color: #993333;">const myFunctionArgs_t args ) {

    <span style="color: #993333;">const <span style="color: #993333;">int valueA = args.<span style="color: #202020;">valueA ? args.<span style="color: #202020;">valueA : <span style="color: #cc66cc;">1;

    <span style="color: #993333;">const <span style="color: #993333;">int valueB = args.<span style="color: #202020;">valueB ? args.<span style="color: #202020;">valueB : <span style="color: #cc66cc;">2;

    <span style="color: #993333;">const <span style="color: #993333;">int valueC = args.<span style="color: #202020;">valueC ? args.<span style="color: #202020;">valueC : <span style="color: #cc66cc;">3;

}

<span style="color: #339933;">#define MyFunction( ... ) MyFunction( ( myFunctionArgs_t ){ __VA_ARGS__ } )

 

MyFunction( .<span style="color: #202020;">valueB = <span style="color: #cc66cc;">4, <span style="color: #cc66cc;">5 ); /* valueA == 1, valueB == 4, valueC == 5 */

MyFunction( .<span style="color: #202020;">valueC = <span style="color: #cc66cc;">6, .<span style="color: #202020;">valueA = <span style="color: #cc66cc;">7, <span style="color: #cc66cc;">8 ); /* valueA == 7, valueB == 8, valueC == 6 */

MyFucntion( .<span style="color: #202020;">valueC = <span style="color: #cc66cc;">9 ); /* valueA == 1, valueB == 2, valueC == 9 */
Study those calls at the bottom of that last code block. Because C structs can be built with .member = we can have some amazing function calls. This is massively useful at work where my 3D engine may need to create an object with all default value except for the position when position is the last value to be set on the list. This is a huge leap over C++ in my opinion, however the zero draw-back is pretty damaging, so it depends on what you want.

Extra:
This form of default arguments is compatible with C-With-Classes function pointers, handy!

So from all this discussed and shown in the thread you can actually start translating C++ libraries into C. I have already translated C++ STL's vector class into a C version (With pointers used as the containers, you can't win them all).

Again, the question of why bother doing this when C++ exists is a big one, use C++ if you can, it's designed to do this stuff, but when C++ isn't an option and you need this OOP approach in C, then you have this thread as a guide.

If anyone has any questions on how other C++ features can be emulated in C, please write them and I'll have a think about it.
If it's lambda functions you're going to suggest then go away, those are ugly in every language I've seen, they're going to be worse in C (There's an easy method for GCC, but it only exists on GCC).
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top