So just for the sake if having ''fun'' I decided to emulate C++ member functions in C using pointer functions. Here is a simple code:
obj.h:
#ifndef OBJ_H
#define OBJ_H
#include <stdlib.h>
#include <stdio.h>
struct Obj{
struct pObjVar* pVar;
void (*read)(struct Obj*);
void (*set) (struct Obj*, int);
};
struct Obj* newObj();
void deleteObj(struct Obj** obj);
#endif
obj.c:
#include "obj.h"
void readValue(struct Obj* this_);
void setValue (struct Obj* this_, int mValue_);
struct pObjVar{
int mValue;
};
struct Obj* newObj(){
struct Obj* tmp = (struct Obj*) malloc(sizeof(struct Obj));
tmp->pVar = (struct pObjVar*) malloc(sizeof(struct pObjVar));
tmp->pVar->mValue = 0;
tmp->read = readValue;
tmp->set = setValue;
return tmp;
}
void deleteObj(struct Obj **obj){
free((*obj)->pVar); (*obj)->pVar = NULL;
free((*obj)); *obj = NULL;
}
void readValue(struct Obj *this_){
printf("Value = %d\n",this_->pVar->mValue);
}
void setValue(struct Obj *this_, int mValue_){
this_->pVar->mValue = mValue_;
}
main.c:
#include "obj.h"
int main(void)
{
struct Obj* a = newObj();
a->set(a, 10);
a->read(a);
deleteObj(&a);
return 0;
}
Output:
>./a.out
Value = 10
In doing this, however, I figured I had to emulate the role of implicit this pointer by explicitly passing it to my member functions. This works fine, I guess, except that it makes the whole thing look weird!
If I wanted to pass the object, why would implement the functions as member functions? The only answer I found to it was maybe in cases where you would want to have a unified interface but various implementations? (something similar to C++ virtual functions?)
What are (if any) some other reasons to emulate member functions? Also, is there any way to get around passing the explicit this_ pointer at all?
EDIT: There was problem in the original code when passing the object. I was using &a by mistake for the read/set functions. You would only need it for the deleteObj if you want to set the pointer to NULL internally.
Just another way of writing:
#define member(FUNC, ...) FUNC(this_, ## __VA_ARGS__)
int reader(struct Obj *_this) {
member(read, a, b, c);
member(getch);
return 0;
}
This can be used for implementing interfaces, inheritance and many C++ features, which were implemented like this in C with Classes times. In Linux kernel, file operations are implemented like this. File structure stores pointers to functions, so that each file system can store it's own system call handlers that operate on/with the data in the structure.
No, there is no way to do this automatically in C. The standard preprocessor is not competent enough to do the transformations.
There is also now way for a function to find out that it was called like a->func(10). Inside the function it is just func(10).
When Bjarne Stroustrup started designing C++, he wrote a special preprocessor/compiler Cfront for this.
In reality, C++ doesn't really store pointers to (non-virtual) functions. It just transforms a->set(10) to something like struct_Obj_set(a, 10) while compiling the code.
Related
We have an anonymous type, typedefed to void *, which is the handle for an API (all code in C11). It is deliberately void * as what it is pointing to changes depending on the platform we are compiled for and we also don't want the application to try dereferencing it. Internally we know what it should be pointing to and we cast it appropriately. This is fine, the code is public, we've been using it for years, it cannot be changed.
The problem is that we now need to introduce another one of these, and we don't want the user to get the two confused, we want the compiler to throw an error if the wrong handle is passed to one of our functions. However, all of the versions of all of the C compilers I have tried so far (GCC, Clang, MSVC) don't care; they know that the underlying type is void * and so anything goes (this is with -Wall and -Werror). Putting it another way, our typedef has not achieved anything, we might as well have just used void *. I have also tried Lint and CodeChecker, who also don't seem to care (though you could probably question my configurations for these). Note that I am not able to use -Wpedantic as we include third party code where that wouldn't fly.
I have tried making the new thing a specific typedefed pointer rather than a void * but that doesn't entirely fix things as the compiler is still happy for the caller to pass that new specific typedefed pointer into the existing functions that are expecting the existing handle typedef.
Is there (a) a way to construct a new anonymous handle such that the compiler will not allow it to be passed to the existing functions or (b) a checker that we can apply to pick the problem up, at least in our own use of these APIs?
Here is some code to illustrate the problem:
#include <stdlib.h>
typedef struct {
int contents;
} existingThing_t;
typedef void *anonExistingHandle_t;
typedef struct {
char contents[10];
} newThing_t;
typedef void *anonNewHandle_t;
typedef newThing_t *newHandle_t;
static void functionExisting(anonExistingHandle_t handle)
{
existingThing_t *pThing = (existingThing_t *) handle;
// Perform the function
(void) pThing;
}
static void functionNew(anonNewHandle_t handle)
{
newThing_t *pThing = (newThing_t *) handle;
// Perform a new function
(void) pThing;
}
int main() {
anonExistingHandle_t existingHandle = NULL;
anonNewHandle_t newHandleA = NULL;
newHandle_t newHandleB = NULL;
functionExisting(existingHandle);
functionNew(newHandleA);
// These should result in a compilation error
functionExisting(newHandleA);
functionNew(existingHandle);
functionExisting(newHandleB);
return 0;
}
Is there (a) a way to construct a new anonymous handle such that the compiler will not allow it to be passed to the existing functions
Yes, use a type that can't be implicitly converted to void *. Use a structure.
typedef struct {
struct newThing_s *p;
} anonNewHandle_t;
Anyway, your design is just flawed and disables all static compiler checks. Do not use void *, instead use structures or structures with void * inside, to enable compile checks. Research how the very, very standard FILE * works. FILE is not void.
Do not use typedef pointers. They are very confusing. https://wiki.sei.cmu.edu/confluence/display/c/DCL05-C.+Use+typedefs+of+non-pointer+types+only
I suggest rewriting your library so that you do not use void * and do not use typedef pointers.
The design, may look like the following:
// handle.h
struct handle_s;
typedef struct {
struct handle_s *p;
} handle_t;
handle_t handle_init(void);
void handle_deinit(handle_t t);
void handle_do_something(handle_t t);
// handle.c
struct handle_s {
int the_stuff_you_need;
};
handle_t handle_init(void) {
return (handle_t){
.p = calloc(1, sizeof(struct handle_s))
};
}
void handle_do_something(handle_t h) {
struct hadnle_s *t = h->p;
// etc.
}
// anotherhandle.h
// similar to above
typedef struct {
struct anotherhandle_s *p;
} anotherhandle_t;
void anotherhandle_do_something(anotherhandle_t h);
// main
int main() {
handle_t h = handle_new();
handle_do_something(h);
handle_free(h);
anotherhandle_do_something(h); // compiler error
}
So, I've been having a bit of confusion regarding linking of various things. For this question I'm going to focus on opaque pointers.
I'll illustrate my confusion with an example. Let's say I have these three files:
main.c
#include <stdio.h>
#include "obj.h" //this directive is replaced with the code in obj.h
int main()
{
myobj = make_obj();
setid(myobj, 6);
int i = getid(myobj);
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
struct obj *make_obj(void){
return calloc(1, sizeof(struct obj));
};
void setid(struct obj *o, int i){
o->id = i;
};
int getid(struct obj *o){
return o->id;
};
obj.h
struct obj;
struct obj *make_obj(void);
void setid(struct obj *o, int i);
int getid(struct obj *o);
struct obj *myobj;
Because of the preprocessor directives, these would essentially become two files:
(I know technically stdio.h and stdlib.h would have their code replace the preprocessor directives, but I didn't bother to replace them for the sake of readability)
main.c
#include <stdio.h>
//obj.h
struct obj;
struct obj *make_obj(void);
void setid(struct obj *o, int i);
int getid(struct obj *o);
struct obj *myobj;
int main()
{
myobj = make_obj();
setid(myobj, 6);
int i = getid(myobj);
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
struct obj *make_obj(void){
return calloc(1, sizeof(struct obj));
};
void setid(struct obj *o, int i){
o->id = i;
};
int getid(struct obj *o){
return o->id;
};
Now here's where I get a bit confused. If I try to make a struct obj in main.c, I get an incomplete type error, even though main.c has the declaration struct obj;.
Even if I change the code up to use extern, It sill won't compile:
main.c
#include <stdio.h>
extern struct obj;
int main()
{
struct obj myobj;
myobj.id = 5;
int i = myobj.id;
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
So far as I can tell, main.c and obj.c do not communicate structs (unlike functions or variables for some which just need a declaration in the other file).
So, main.c has no link with struct obj types, but for some reason, in the previous example, it was able to create a pointer to one just fine struct obj *myobj;. How, why? I feel like I'm missing some vital piece of information. What are the rules regarding what can or can't go from one .c file to another?
ADDENDUM
To address the possible duplicate, I must emphasize, I'm not asking what an opaque pointer is but how it functions with regards to files linking.
Converting comments into a semi-coherent answer.
The problems with the second main.c arise because it does not have the details of struct obj; it knows that the type exists, but it knows nothing about what it contains. You can create and use pointers to struct obj; you cannot dereference those pointers, not even to copy the structure, let alone access data within the structure, because it is not known how big it is. That's why you have the functions in obj.c. They provide the services you need — object allocation, release, access to and modification of the contents (except that the object release is missing; maybe free(obj); is OK, but it's best to provide a 'destructor').
Note that obj.c should include obj.h to ensure consistency between obj.c and main.c — even if you use opaque pointers.
I'm not 100% what you mean by 'ensuring consistency'; what does that entail and why is it important?
At the moment, you could have struct obj *make_obj(int initializer) { … } in obj.c, but because you don't include obj.h in obj.c, the compiler can't tell you that your code in main.c will call it without the initializer — leading to quasi-random (indeterminate) values being used to 'initialize' the structure. If you include obj.h in obj.c, the discrepancy between the declaration in the header and the definition in the source file will be reported by the compiler and the code won't compile. The code in main.c wouldn't compile either — once the header is fixed. The header files are the 'glue' that hold the system together, ensuring consistency between the function definition and the places that use the function (references). The declaration in the header ensures that they're all consistent.
Also, I thought the whole reason why pointers are type-specific was because the pointers need the size which can vary depending on the type. How can a pointer be to something of unknown size?
As to why you can have pointers to types without knowing all the details, it is an important feature of C that provides for the interworking of separately compiled modules. All pointers to structures (of any type) must have the same size and alignment requirements. You can specify that the structure type exists by simply saying struct WhatEver; where appropriate. That's usually at file scope, not inside a function; there are complex rules for defining (or possibly redefining) structure types inside functions. And you can then use pointers to that type without more information for the compiler.
Without the detailed body of the structure (struct WhatEver { … };, where the braces and the content in between them are crucial), you cannot access what's in the structure, or create variables of type struct WhatEver — but you can create pointers (struct WhatEver *ptr = NULL;). This is important for 'type safety'. Avoid void * as a universal pointer type when you can, and you usually can avoid it — not always, but usually.
Oh okay, so the obj.h in obj.c is a means of ensuring the prototype being used matches the definition, by causing an error message if they don't.
Yes.
I'm still not entirely following in terms of all pointers having the same size and alignment. Wouldn't the size and alignment of a struct be unique to that particular struct?
The structures are all different, but the pointers to them are all the same size.
And the pointers can be the same size because struct pointers can't be dereferenced, so they don't need specific sizes?
If the compiler knows the details of the structure (there's a definition of the structure type with the { … } part present), then the pointer can be dereferenced (and variables of the structure type can be defined, as well as pointers to it, of course). If the compiler doesn't know the details, you can only define (and use) pointers to the type.
Also, out of curiosity, why would one avoid void * as a universal pointer?
You avoid void * because you lose all type safety. If you have the declaration:
extern void *delicate_and_dangerous(void *vptr);
then the compiler can't complain if you write the calls:
bool *bptr = delicate_and_dangerous(stdin);
struct AnyThing *aptr = delicate_and_dangerous(argv[1]);
If you have the declaration:
extern struct SpecialCase *delicate_and_dangerous(struct UnusualDevice *udptr);
then the compiler will tell you when you call it with a wrong pointer type, such as stdin (a FILE *) or argv[1] (a char * if you're in main()), etc. or if you assign to the wrong type of pointer variable.
For example, I have the C code below:
#include <stdio.h>
#include <stdlib.h>
struct a
{
void(*fun)(struct a *);
int x;
};
void fun(struct a *st)
{
++st->x;
}
struct a *new_a()
{
struct a *v = (struct a*)malloc(sizeof(struct a));
v->fun = fun;
return v;
};
int main()
{
struct a *v = new_a();
v->x = 5;
v->fun(v);
printf("%d\n", v->x);
}
This prints, of course, 6, however, is there a way of not making the function call dependent of using the same struct to call it: v->fun();, rather than v->fun(v);?
The short answer is no. You would need C++ for that.
No. In C there is no easy way to do this. C++ provides this feature, it's called methods. If you are going to implement your own C with classes, you'll run into a syntax nightmare, before giving up.
A good C-style approach to object-functions will be the convention for functions taking one (mostly the first) parameter as a "self" (which is the reference to the object that gets managed).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How could one implement C++ virtual functions in C
In C++ the only difference between a class and a struct is the default access level. So you can have virtual functions in structures, inherit from structures and so on. My question is, can you also do this in C?
You can do "virtual functions" with function pointers stored in your structs. For inheratince, you can embed a struct in another struct but the syntax, again, is going to be different than what you would expect. You can write object-oriented programs in C (classic example is the unix file/socket/... API), but with a quite awkward syntax.
Relevant answers here: https://stackoverflow.com/search?q=C+virtual+functions
C has no native syntax for virtual methods. However, you can still implement virtual methods by mimicking the way C++ implements virtual methods. C++ stores an additional pointer to the function definition in each class for each virtual method. Thus, you can simply add a function pointer to a struct to simulate virtual methods.
For example
#include <stdio.h>
#include <stdlib.h>
int f2(int x)
{
printf("%d\n",x);
}
typedef struct mystruct
{
int (*f)(int);
} mystruct;
int main()
{
mystruct *s=malloc(sizeof(mystruct));
s->f=f2;
s->f(42);
free(s);
return 0;
}
No you can't. 'virtual' is not part of the C vocabulary, neither is 'access level'
You can simulate virtual functions with function pointers. For instance,
struct foo
{
void(*bar)(struct foo*, int, int);
};
void default_bar ( struct foo * f, int a, int b )
{
printf("bar(%d,%d)\n", a, b);
}
void setup_foo ( struct foo * f )
{
f->bar = &default_bar;
}
Then, you can "subclasss" the structure with something like:
struct meh
{
/* inherit from "class foo". MUST be first. */
struct foo base;
int more_data;
};
/* override "method bar". */
struct custom_bar ( struct foo * f, int a, int b )
{
struct meh * m = (struct meh*)f;
printf("custom_bar(%d,%d)\n", a, b);
}
void setup_meh ( struct meh * m )
{
setup_foo(&m->base);
m->bar = &custom_bar;
}
All of this is labor-intensive and error prone, but it can be done. This type of "inheritance" and "override" implementation is common practice in some well-known C libraries, including jpeglib and libpng. They use this technique to allow you to override the I/O procedures if you're not satisfied with standard C I/O.
Edit: as noted in the comments, some of this code relies on (officially) non-standard behavior that "just happens" to work on most compilers. The main issue is that the code assumes that &m.base == &m (e.g. the offset of the base member is 0). If that is not the case, then the cast in custom_bar() results in undefined behavior. To work around this issue, you can add an extra pointer in struct foo as such:
struct foo
{
/* same as before ...*/
/* extra pointer. */
void * hook;
};
Then, modify the stuff that touches the cast,
void setup_meh ( struct meh * m )
{
m->base.hook = m;
/* set up function pointers as usual... */
}
void custom_bar ( struct foo * f, int a, int b )
{
struct meh * m = (struct meh*)f->hook;
/* override. */
}
This technique is more reliable, especially if you plan to write the "derived struct" in C++ and use virtual functions. In that case, the offset of the first member is often non-0 as compilers store run-time type information and the class' v-table there.
You can not. C structs can not have behaviors. They can only have data.
Please see http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=tenBestQuestions
for differences between C structs and C++ structs.
it is written in the second question.
C++ structures is as different as C++ classes are different from C structs. It's just an analogy.
Plus there's no such thing as inheritence in C. Without inheritence, what would you do with virtual functions?
I am not sure that what I am trying to do is called encapsulation, but it's an OOP concept. I am implementing a binary tree and in particular the insert function:
typedef struct __node* tree;
typedef struct __node { void* data; tree l,r; } node;
typedef struct {int (*cmp)(void* a,void* b); tree root;} avl_tree;
....
void tree_insert(tree node, tree* root, int (*cmp)(void* a,void* b))
{
if (*root==NULL) { *root=node; return; }
int c1 = cmp(node->data, (*root)->data);
if (c1==-1) tree_insert(node, &((*root)->l), cmp);
}
tree tree_new_node(void*data){ tree a = malloc(...); ... return a; }
void avl_insert(void* data, avl_tree* a)
{
tree_insert(tree_new_node(data), &(a->root), a->cmp);
....
}
The module is to be used through the avl_insert function which is given a pointer to the relevant balanced tree avl_tree which contains the pointer to the raw tree as well as a pointer to comparator. Now, it should obviously call tree insert and tree_insert should have access to the comparator as well as to the node I am currently inserting. The function walks on a binary tree so it's naturally recursive. However, if I give it the comparator and the current node as parameters they will be passed with each recursive invocation which is not necessary since they will always be the same.
I would like to avoid having to do so. I have not been able to come up with a clean and nice solution. These are the options that I could think of:
Use a C++ class and have the tree_insert function be a method of avl_tree class. Then it would have access to the comparator through the this pointer. The problem with this solution is that I want to use C not C++. Besides, it won't eliminate the passing of the current node parameter.
Use static members inside the function (or global data). I am not sure I can cleanly initialize them at each avl_insert call. Besides, this solution is not thread safe.
Now that I think about it this seems very easy to implement in a functional programming language. I wonder, is this a fundamental problem with C or is it just me not knowing how to do it. What would be the cleanest way to achieve this?
Thank you!
After I thought about Victor Sorokin's answer I read about the this pointer and it turns out it is an implicit parameter in every member function call. Now that I think about it it seems the only logical solution. Each invocation of the tree_insert function needs to know the address of the structure it's operating on. Not even in a functional language could you avoid that extra pointer...
A possible solution would be to keep a pointer to the main tree structure in each node..
So it's a fundamental "problem".
One fun approach that could be used to achieve encapsulation is looking into assembly code emitted by C++ compiler and then translating it into appropriate C code.
Another, more conventional, approach would be to use some C object library, like GLib.
I think, though, these two methods will give similar results :)
By the way, first option you mentioned is just as vulnerable to threading issues as second. There's no implicit thread-safety in C++.
"OOP" C code I have seen in Linux kernel (file-system layer) is mostly concerned with polymorphism, not with encapsulation. Polymorphism is achieved by introducing structure enumerating possible operations (as pointers to functions). Various "subclasses" then created, each initializing this structure with it's own set of implementation methods.
You should be able to convert that tail recursion to iteration, and avoid the function calls altogether. Something like
void tree_insert(tree node,tree*root,int (*cmp)(void*a,void*b))
{
tree* current = root;
while (*current != NULL)
{
int c1=cmp(node->data,(*current)->data);
if(c1==-1)current = &((*current)->l);
else current = &((*current)->r);
}
*current=node;
}
There is already a question covering my answer—What does “static” mean in a C program?
You can roughly take a C source file as a class. The keyword static makes the variable or function have only internal linkage, which is similar to private in classical OOP.
foo.h
#ifndef FOO_H
#define FOO_H
double publicStuff;
double getter (void);
void setter (double);
int publicFunction (void);
#endif
foo.c
#include "foo.h"
static double privateStuff;
static int privateFunction (void)
{
return privateStuff;
}
int publicFunction (void)
{
return privateFunction();
}
double getter (void)
{
return privateStuff;
}
void setter (double foo)
{
privateStuff = foo;
}
main.c
#include "foo.h"
#include <stdio.h>
static double privateStuff = 42;
static int privateFunction (void)
{
return privateStuff;
}
int main (void)
{
publicStuff = 3.14;
setter(publicStuff);
printf("%g %d %d\n", getter(), publicFunction(), privateFunction());
return 0;
}