Is there a way to have some kind of default constructor (like a C++ one) for C user types defined with a structure?
I already have a macro which works like a fast in
Using functions to create and dispose of structures has already been mentioned. But in a comment you mentioned that you wanted a "default constructor" - I think you mean that you want to initialize some (all?) of the struct fields to default values.
This is done in C using some coding convention -- either functions, macros, or a mix. I usually do it something like the following --
struct some_struct {
int a;
float b;
};
#define some_struct_DEFAULT { 0, 0.0f}
struct some_struct *some_struct_create(void) {
struct some_struct *ptr = malloc(sizeof some_struct);
if(!ptr)
return ptr;
*ptr = some_struct_DEFAULT;
return ptr;
}
// (...)
struct some_struct on_stack = some_struct_DEFAULT;
struct some_struct *on_heap = some_struct_create();
You can create initializer functions that take a pointer to a structure. This was common practice.
Also functions that create a struct and initialize it (like a factory) - so there is never a time where the struct is "uninitialized" in the "client" code. Of course - that assumes people follow the convention and use the "constructor"/factory...
horrible pseudo code with NO error checking on malloc or free
somestruct* somestruct_factory(/* per haps some initializer agrs? */)
{
malloc some stuff
fill in some stuff
return pointer to malloced stuff
}
void somestruct_destructor(somestruct*)
{
do cleanup stuff and also free pointer
free(somestruct);
}
Someone will probably come along and explain how some early C++ preprocessors/compilers worked to do this all in C.
Not really. If I remember correctly, the closest you get to classes are structures. You allocate memory and populate the fields. I don't see how you would make a generic constructor type thing for this. Theoretically, you could write a macro which would do some of this. Not sure if that is really worthwhile though.
Here's a little macro magic around malloc()
, memcpy()
and C99 compound literals:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define new(TYPE, ...) memdup(&(TYPE){ __VA_ARGS__ }, sizeof(TYPE))
void * memdup(const void * obj, size_t size)
{
void * copy = malloc(size);
return copy ? memcpy(copy, obj, size) : NULL;
}
struct point
{
int x;
int y;
};
int main()
{
int * i = new(int, 1);
struct point * p = new(struct point, 2, 3);
printf("%i %i %i", *i, p->x, p->y);
return 0;
}
No, structs are nothing but a bunch of data. You cannot declare functions within the structs, so there is no way to create a constructor for it.
Basically, C++ creates lists of pointers which contain the addresses of methods. This list is called a class definition (there is some more data in the class def, but we ignore that for now).
A common pattern to have "classes" in pure C is to define a "struct class". One of the fields of the struct is a factory function which returns "instances" of the class. I suggest to use a macro to hide the casts:
typedef struct __class * class;
typedef void (*ctor_ptr)(class);
struct class {
char * name;
ctor_ptr ctor;
... destructor and other stuff ...
}
#define NEW(clz) ((struct something *)(((struct class *)clz)->ctor(clz)))
Now, you can define the classes you have by creating structures of type "struct class" for each class you have and then call the constructor stored in them. The same goes for the destructor, etc.
If you want methods for your instances, must put them into the class structures and keep a pointer to the class in the instance struct:
#define NEW_SOMETHING() ((struct something *)NEW(&something_definition))
#define METHOD(inst, arg) ((struct something_class *)(((struct something *)inst)->clz)->method(inst, arg))
NEW_SOMETHING
will create a new instance of "something" using the class definition stored in the structure something_definition
. METHOD will invoke a "method" on this instance. Note that for real code, you will want to check that inst
is actually an instance of something
(compare the class pointers, something like that).
To have inheritance is a bit tricky and left as an exercise for the reader.
Note that you can do everything you can do in C++ in pure C. A C++ compiler does not magically replace your CPU with something else. It just takes a lot more code to do it.
If you want to look at an example, check out glib (part of the Gtk+ project).