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:
Using C structures, we can somewhat emulate this:
Things to note:
The implementation of this particular class in C++ can be something like this:
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.
Things to note:
To use this class, C++ we have
And in C
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
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 );
};
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();
- 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;
}
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;
}
- 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 );
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