54

Given:

struct objStruct {
    int id;
    int value;
};

typedef struct objStruct Object;

Is there a shortcut to allocate and initialize the object, something like a C++ constructor?
It could even be a preprocessor macro. Whatever makes the code shorter and more readable than this:

Object *newObj = malloc(sizeof(Object));
// successful allocation test snipped
newObj->id = id++;
newObj->value = myValue;
Aillyn
  • 23,354
  • 24
  • 59
  • 84
  • duplicate of [Constructor in C](http://stackoverflow.com/questions/537244/constructor-in-c), [Initialising C structures](http://stackoverflow.com/questions/1994841/initialising-c-structures) – outis Sep 22 '10 at 23:28
  • 2
    Neither of the possible duplicates ([Default constructor in C](http://stackoverflow.com/questions/537244/) or [Initialising C structures in C++ code](http://stackoverflow.com/questions/1994841/)) is really a good duplicate for this, though they are related. They've been retitled since the previous comment was made. – Jonathan Leffler Dec 22 '14 at 18:50

6 Answers6

61

In C I typically create a function in the style of a constructor which does this. For example (error checking omitted for brevity)

Object* Object_new(int id, int value) { 
  Object* p = malloc(sizeof(Object));
  p->id = id;
  p->value = value;
  return p;
}

...
Object* p1 = Object_new(id++, myValue);
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 6
    It may be a bit overkill, but I usually also create a void objStruct_destroy(objStruct * obj) that does free for me, in case I need to add any freeing for allocated structs inside later. – Mike Axiak Sep 22 '10 at 22:56
  • 13
    Yes; except that it's sometimes preferable to have the "constructor" take the Object* as a parameter instead, so you can do stack allocation as well (`Object object; Object_initialise(&object);`). – Porculus Sep 22 '10 at 22:57
  • 2
    An intermediate method would be have an Object_Init to perform initialization on an already allocated object (=placement constructor), and Object_New to allocate and init (internally it should call Object_Init). The same should be done for the "destructor". – Matteo Italia Sep 22 '10 at 23:01
  • From the perspective of a beginner: Is there a reason why you are giving back the pointer and not the object/struct itself? – ASA Nov 30 '14 at 18:51
  • @Traubenfuchs because it would mean making a copy at the point of return. It could be [elided](https://en.wikipedia.org/wiki/Copy_elision), but that's not guaranteed. – Ruslan Jan 05 '16 at 12:01
  • What you need to keep in mind is to check for errors using assert() – Sayan Bhattacharjee Apr 18 '16 at 22:06
  • If you take this approach you will have to remember to free that memory to avoid having memory leaks. – Tono Nam Jun 02 '22 at 15:27
36

In C99 and beyond, you can use a compound literal, which looks like a cast followed by an initializer in braces:

int init_value = ...;
int init_id    = ...;
Object newObj1 = (Object){ .value = init_value, .id = init_id };
Object newObj2 = (Object){ .id = init_id, .value = init_value };

The latter two lines achieve the same effect - the order of the fields is not critical. That is using 'designated initializers', another C99 feature. You can create a compound literal without using designated initializers.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
11

In C it is possible to declare an inline function with the same name as structure:

struct my
{
    int a;
};

inline struct my* my(int* a)
{
    return (struct my*)(a);
}

//somewhere in code
int num = 123;
struct my *sample = my(&num);
//somewhere in code

It looks pretty similar to C++ ctors.

grekhss
  • 165
  • 1
  • 11
  • 1
    How does `return (struct my*)(a)` setup the `int a`? Shouldn't it be assigned by `pointer_to_my->a`? – NeoZoom.lua Feb 17 '21 at 08:23
  • That's just a simulation of ctor: the address of num is interpreted as a pointer to a struct which consists of one field - integer. This trick will not work if one adds another field into the struct, e.g. integer or, say, a pointer: passing address into function my() will lead to a garbage in extra field. – grekhss Feb 18 '21 at 09:56
  • ok, but from a C file I get `Undefined symbol: _my`; no error if I remove the `inline` keyword – tontonCD May 12 '22 at 18:35
4
struct thingy {
   char * label;
   int x;
};

#define declare_thingy( name, label, val) struct thingy name = { label, val }

struct thingy * new_thingy(const char * label, int val) {
     struct thingy * p = malloc(sizeof(struct thingy));
     if (p) {
          p->label = label;
          p->val = val;
     }
     return p;
}
nategoose
  • 12,054
  • 27
  • 42
2

You really have to distinguish initialization of static or auto variables and dynamic allocation on the head. For the first, do named initializers, for the second a well specified init function.

All that can be nicely packed into macros do give you an easy static/auto intialization and something similar to new in C++.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

If you are looking for an object oriented "emulation" over C, I strongly recommend the GObject Type System [1], it's mature and largely used by GTK for instance.

GLib [2] has also a nice slice allocator for small objects, currently used by GNOME.

[1] GObject Reference Manual

[2] GLib Memory Slices

Tarantula
  • 19,031
  • 12
  • 54
  • 71
  • Be aware though that some things which are normally checked at compile time in C++, are done only at run time in GObject. – Ruslan Jan 05 '16 at 12:27