0

This is what I want to do:

1) I want a function that instantiates a data structure.

void instantiateCDB(void);

2) I also want a function that updates the data structure that is instantiated and returns a const pointer to the data structure (to make it read-only)

I know that this can be done in C++/Java. But can it also be done in C?

The program flow that I want to write is:

main(){
   instantiateCDB();    // Allocates a CDB 
   const struct canDataBlock * cdb = getUpdateSystem();
}

// But the best function definitions that I can come up with is this.

struct canDataBlock * instantiateCDB() {
     static struct canDataBlock cdb = {0};
     return &cdb;
}

const struct canDataBlock * getUpdateSystem() {

     struct canDataBlock * cdb = instantiateCDB();
     return &cdb;
 }

The problem is: How do I access the data structure with write/read access instantiated in the instantiateCDB function if it would be declared void? If I am going to return the allocated data structure, the user can alter the canDataBlock thus losing its integrity. What I want to happen is only the getUpdateSystem() can change the values of the data structure instantiated by the instantiateCDB() function. How do I solve this problem? Is there another technique in C that I do not know about. If there is, please teach me. :)

Casper Beyer
  • 2,203
  • 2
  • 22
  • 35
Xegara
  • 563
  • 2
  • 10
  • 23
  • 1
    usually you would do this with function pointers - http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work. your "classes" (structs) will have an array of function pointers, with each type pointing to different functions. – radai Oct 06 '13 at 08:28
  • 2
    removing `[java]` and `[c++]` as the answer won't have anything to do with those. The best way to use OO is to use C++. – Peter Lawrey Oct 06 '13 at 08:33
  • 2
    Are you using [opaque pointers](http://en.wikipedia.org/wiki/Opaque_pointer)? If yes, I don't see where the problem is. If no, here's your [solution](http://stackoverflow.com/questions/7553750/what-is-an-opaque-pointer-in-c). – anatolyg Oct 06 '13 at 08:45
  • @PeterLawrey Unfortunately, I'm programming this to a microcontroller and so I'm stuck with C. – Xegara Oct 06 '13 at 08:46
  • @radai Can you explain further? :) I'm only a beginner to function pointers and know how to make callback functions. – Xegara Oct 06 '13 at 08:47
  • The code in your question isn't going to work. The struct `cdb` goes out of scope at the end of `instantiateCDB`, so it will be gone from the stack. The pointer returned from `instantiateCDB` will be a dangling pointer - a serious bug. If you want to pass pointers to a struct around, its usually better to `malloc` some space on the heap for the struct, rather than using stack space for it. – Dawood ibn Kareem Oct 06 '13 at 08:48
  • So the "class oriented approach" in your title refers to encapsulation? If so, please edit so that others can know exactly what this question is about. – Theodoros Chatzigiannakis Oct 06 '13 at 08:48

2 Answers2

2

There's a pattern called opaque data pointer, it might help you here. See http://en.wikipedia.org/wiki/Opaque_data_type.

vines
  • 5,160
  • 1
  • 27
  • 49
2

OO in C can be partly simulated (word "simulation" rather than "implementation" was chosen deliberately), for example inheritance can be simulated by nesting base struct as a first member of "derived" struct, in such case it is possible to "upcast" derived pointer struct to "base" struct as in C there is guarantee that pointer to struct can be used to access pointer to first member. Depending on the context, you may use opaque data type to hide implementation details. To simulate private and public data you can provide full struct declaration, including all members, but still hide some members as a opaque or void pointer.

struct myclass_privdata;
struct myclass { int data; /* public member */ 
struct myclass_privdata* data_priv; /* private simulation*/ }

You can also simulate member functions by using function pointers, but you still need to pass explicitly object reference (and initialize it too).

struct S;
void do(struct S* this_p) { }
struct S { void (*do_smth)(struct s* this_p); } s;
s->do_smth = do;
s->do_smth(s);

Probably you can found inspiration in glib library object model. Also there is even a book about this topic.

However, the best advice existing for this topic, is to stay with the language style, rather than trying to do things the language is not supposed to be used (for example, implementing oop in C often results in boilerplate code which adds low functional value - it makes code looking like it is written in OOP when in fact it is not, and makes code looking ugly for those who program in "native" style).

Addressing your question.

1) Function returning data instance is typically implemented as function which returns malloced() pointer

#include <stdlib.h>
struct S {int i; };
struct S* S_alloc(void) { return malloc(sizeof(S)); }

Your code which returns pointer to static data is almost for sure a trouble as all references will refer to same object. And judging by void instantiateCDB(void); declaration I doubt it does really what you want to do.

2) I doubt that you really "want a function that updates the data structure that is instantiated and returns a const pointer to the data structure (to make it read-only)" - because caller will still have a non-const pointer which was just passed to such function.

mfxm
  • 184
  • 4