tags:

views:

3121

answers:

12
+5  Q: 

Constructor in C

Is there a way to have some kind of default constructor (like C++ one) for C user types defined with a structure?

I already have a macro which works like fast initializer (like pthread_mutex's one) but i wanted to know if you can by any chance have some (or all) fields of a struct filled at declaration.

For instance with the pthread_mutex example, I would like

pthread_mutex_t my_mutex;

To have the same effect than

pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
+6  A: 

No, not directly. The closest you could do is to write a function that allocated an instance and populated some of the fields.

ConcernedOfTunbridgeWells
+4  A: 

You can write a function that returns the C struct:

struct file create_file(int i, float f) {
    struct file obj = { i, f };
    // other code here...
    return obj;
}

If you wonder whether you can have "normal" member functions in C. Well, you can to some extent. I prefer the object-as-first-argument style. You pass a pointer to your struct as the first argument. This way, you can have several functions, defining the interface to your objects:

int file_get_integer(struct file *self) { return self->i; }
float file_get_float(struct file *self) { return self->f; }

If you write in that style, what you have at the end is an abstract data-type. I've seen guys emulating the member function call syntax used in C++ by having function pointers into their struct and then doing:

obj.get_integer(&obj);

It's used by the linux kernel for defining the interface to file system drivers. It's a style of writing that one may like, or may not like. I don't like it too much, because i keep using members of structures for data and not for emulating member functions calls to look like in popular object oriented languages.

Johannes Schaub - litb
Hopefully your compiler is smart enough to avoid copying the entire structure in the return statement.
joeforker
As joeforker indirectly points out, it's better to use a pointer than a blanket return statement. What if your struct is particularly large? Most compilers will copy the return value.
Randolpho
if it is very large i would make it take a pointer. but in this case (and possibly nearly all other cases) it's quite small. i would put large amount of data on the heap and put a pointer into the struct anyway.
Johannes Schaub - litb
don't forget that passing pointers will interfere with aliasing, which also requires a smart compiler to optimize. for small structs, i would suspect you can even have a performance benefit in some cases if it's returned directly. named return value optimization will make the copy superfluous too.
Johannes Schaub - litb
+16  A: 

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.

Tim
Oh cfront, how we miss you.
joeforker
... like a horrible burning rash.
Randolpho
And how does cfront handled constructor at the beginning?
claferri
my mistake, my question was about default constructor, i would like to have some field of a struct initialized at declaration without having to call a constructor.
claferri
typedef struct { int x; char c; float f; } t_myStruct;t_myStruct foo = { 0, 'q', 7.3f };
plinth
A: 

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.

soulmerge
You can include functions in structs in C, or at least function pointers. You can put constructors in them, and call them by convention. Last time I saw somebody do that it was a real mess, and didn't look worth it to me, but you can do it.
David Thornley
-2 seems harsh for something that's perfectly correct. +1 for justice.You could put in a function pointer called "constructor", but you'd still have to tell it to point to a global function before you called it, so you might as well call the global function directly! Also, you wouldn't get "this".
MrZebra
+1 from me too.. while it is possible to get creative with function pointers, there is very little reason to do so.
Tim Post
it's totally wrong: a) you _can_ relate functions to structs. b) that's not the question c) there are _lots_ of way to do this, so it's terribly wrong to say "there is no way"
Javier
no. this guy is right: you cannot have functions within structs, but only "a bunch of data". he did not say you can't relate functions to structs. it's what you invented and accuse him saying that. and yes there is no way to have a default constructor, for example.
Johannes Schaub - litb
The question was whether a struct can have a constructor in C, wasn't it? Of course there are tons of equivalent constructs for this, but there is absolutely no way to actually define a constructor in the struct. Once more: The question was not "How do I initialize a struct?"
soulmerge
+1  A: 

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.

paul
Can you develop your macro idea ?
claferri
ever heard of factory functions? a simple function that allocates and populates the struct. no need for macros. in fact, this exactly what C++ constructors do.
Javier
@javier: yes, but only in a Java context. I haven't used C since 1994 and have no wish to go back :)
paul
@claferi: see other posts on this question for macro examples - or use factory functions - or better still use C# or Java :)
paul
+2  A: 

Assuming that you want to do this in C, so your question isn't about structs in C++:

What I usually do is that I just create a function, init_whatever, that takes a pointer to the struct (or other variable), and sets it to the values I want.

If it is a global variable (which is initialized to zero) you could sort of simulate an argument-less constructor by having an "initialized" flag in it, and then let your other functions check that flag, and initialize the struct if the flag is zero. I'm not at all sure that this is a good idea, though.

And, as someone else noted, you could also do something horrible with macros...

Thomas Padron-McCarthy
+3  A: 

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).

Aaron Digulla
Ever heard of GOBJECT?
joeforker
@joe: Ever heard of the Amiga? :)
Aaron Digulla
my mistake, my question was about default constructor, i would like to have some field of a struct initialized at declaration without having to call a constructor.
claferri
@claferri: Ah. Can't have that in ANSI C. For this, you must call a function which allocates and initialized the method.
Aaron Digulla
@joe: Granted, the Amiga had only very simple OO at the C level. gobject really rode the C preprocessor ;)
Aaron Digulla
+4  A: 

C++ is different from C in this case in the respect that it has no "classes". However, C (as many other languages) can still be used for object oriented programming. In this case, your constructor can be a function that initializes a struct. This is the same as constructors (only a different syntax). Another difference is that you have to allocate the object using malloc() (or some variant). In C++ you would simlpy use the 'new' operator.

e.g. C++ code:

class A {
  public:
    A() { a = 0; }
    int a;
};

int main() 
{
  A b;
  A *c = new A;
  return 0;
}

equivalent C code:

struct A {
  int a;
};

void init_A_types(struct A* t)
{
   t->a = 0;
}

int main()
{
   struct A b;
   struct A *c = malloc(sizeof(struct A));
   init_A_types(&b);
   init_A_types(c);
   return 0;
}

the function 'init_A_types' functions as a constructor would in C++.

Reed
+1  A: 

You might want to take a look at a C++ compiler. It gives you more object oriented features than you can remember in a language having a C-like syntax in a more elegant and standard way than trying to bolt constructors and so forth onto C with libraries and macros.

If that doesn't work for you then take a look at GObject. http://en.wikipedia.org/wiki/GObject. It is an object system for C used in GTK and Gnome that pretty much cranks "objects in C" to 11.

From Wikipedia:

The GLib Object System, or GObject, is a free software library (covered by the LGPL) that provides a portable object system and transparent cross-language interoperability.

The system supports constructors, destructors, single inheritance, interfaces, virtual public and private methods and so forth. It's also much more tedious and difficult than doing the same things in C++. Have fun!

joeforker
+2  A: 

Let's talk about the complete engineering solution that was considered best practice in the olden days.

The problem with structs is that everything is public so there is no data hiding.

We can fix that.

You create two header files. One is the "public" header file used by clients of your code. It contains definitions like this:

typedef struct t_ProcessStruct *t_ProcessHandle;

extern t_ProcessHandle NewProcess();
extern void DisposeProcess(t_ProcessHandle handle);

typedef struct t_PermissionsStruct *t_PermissionsHandle;

extern t_PermissionsHandle NewPermissions();
extern void DisposePermissions(t_PermissionsHandle handle);

extern void SetProcessPermissions(t_ProcessHandle proc, t_PermissionsHandle perm);

then you create a private header file that contains definitions like this:

typedef void (*fDisposeFunction)(void *memoryBlock);

typedef struct {
    fDisposeFunction _dispose;
} t_DisposableStruct;

typedef struct {
    t_DisposableStruct_disposer; /* must be first */
    PID _pid;
    /* etc */
} t_ProcessStruct;

typedef struct {
    t_DisposableStruct_disposer; /* must be first */
    PERM_FLAGS _flags;
    /* etc */
} t_PermissionsStruct;

and then in your implementation you can do something like this:

static void DisposeMallocBlock(void *process) { if (process) free(process); }

static void *NewMallocedDisposer(size_t size)
{
    assert(size > sizeof(t_DisposableStruct);
    t_DisposableStruct *disp = (t_DisposableStruct *)malloc(size);
    if (disp) {
       disp->_dispose = DisposeMallocBlock;
    }
    return disp;
}

static void DisposeUsingDisposer(t_DisposableStruct *ds)
{
    assert(ds);
    ds->_dispose(ds);
}

t_ProcessHandle NewProcess()
{
    t_ProcessHandle proc =  (t_ProcessHandle)NewMallocedDisposer(sizeof(t_ProcessStruct));
    if (proc) {
        proc->PID = NextPID(); /* etc */
    }
    return proc;
}

void DisposeProcess(t_ProcessHandle proc)
{
    DisposeUsingDisposer(&(proc->_disposer));
}

What happens is that you make forward declarations for your structs in your public header files. Now your structs are opaque, which means clients can't dick with them. Then, in the full declaration, you include a destructor at the beginning of every struct which you can call generically. You can use the same malloc allocator for everyone the same dispose function and so. You make public set/get functions for the elements you want exposed.

Suddenly, your code is much more sane. You can only get structs from allocators or function that call allocators, which means you can bottleneck initialization. You build in destructors so that the object can be destroyed. And on you go. By the way, a better name than t_DisposableStruct might be t_vTableStruct, because that's what it is. You can now build virtual inheritance by having a vTableStruct which is all function pointers. You can also do things that you can't do in a pure oo language (typically), like changing select elements of the vtable on the fly.

The important point is that there is an engineering pattern for making structs safe and initializable.

plinth
+1  A: 

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;
}
Christoph
+1  A: 

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();
gnud