I have implemented a linked list in C (not C++) that stores pointers to data. I would like to have multiple declarations for its functions (to provide type safety), but have each of them link to the same definition (because there is no actual difference between pointers to different data types, so using the same code reduces space).
Does anyone have any ideas on how to achieve this (or any better ways to do it)? A portable solution is obviously best, but I really just need something that works in GCC.
I believe you might be able to achieve this using typedefs for function prototypes and
casting the generic solution (which deals in void*s) to the specific prototype. This should be safe for compilation because all pointers would be the same size.
Consider this example:
do_something.h:
typedef void (*do_something_with_int_t)(int *i);
extern do_something_with_int_t do_something_with_int;
typedef void (*do_something_with_string_t)(char *s);
extern do_something_with_string_t do_something_with_string;
do_something.c
#include "do_something.h"
void do_something_generic(void* p) {
// Do something generic with p
}
do_something_with_int_t do_something_with_int =
(do_something_with_int_t)do_something_generic;
do_something_with_string_t do_something_with_string =
(do_something_with_string_t)do_something_generic;
As long as do_something_generic is truly datatype-agnostic (i.e. it really doesn't matter what p points to) then this would be OK.
If it's C (not C++), then the following will work just fine. You can adapt the concept to your needs.
tt.h
typedef struct {
int ii;
} Type_1;
typedef struct {
int ii;
} Type_2;
int foo_1(Type_1* ptr) __attribute__((alias("foo")));
int foo_2(Type_2* ptr) __attribute__((alias("foo")));
tt.c
#include <stdio.h>
#include "tt.h"
int main() {
Type_1 t_1;
Type_2 t_2;
foo_1(&t_1);
foo_2(&t_2);
}
int foo(void* arg) {
printf("foo: %p\n", arg);
}
#include <stdio.h>
struct common_type {
int type;
};
struct type1 {
int type;
int value;
};
struct type2 {
int type;
char* p;
};
int func(void *para) {
switch (((struct common_type*)para)->type) {
case 1:
printf("type1,value:%d\n",((struct type1*)para)->value);
break;
case 2:
printf("type2,content:%s\n",((struct type2*)para)->p);
break;
}
}
int main() {
char *s = "word";
struct type1 t1 = {1,1};
struct type2 t2;
t2.type = 2;
t2.p = s;
func((void*)&t1);
func((void*)&t2);
}
Related
I have a c struct that has a const variable.
typedef struct {
u32 status;
const u32 dir_search_idx;} FS_OBJ;
What I would like to do is init the const variable in a function once I have created the struct object. I guess I want to do something similar to what a constructor would do in c++. Is it possible to do something similar in c? Thanks
This should work perfectly fine if you are using C99 or newer and want to initialize the const variable when creating the struct:
FS_OBJ obj = { .status = /* something */, .dir_seach_idx = /* something */ };
You can't modify the const variable after creating the struct. Then you would have to remove the const keyword as mentioned by user3386109 in the comments.
I think const is not the right tool for what you are looking for. You can put data (structs) and behavior (functions) in a *.c file and provide public functions in the corresponding header file. This way you can mimic the equivalent c++ code that you want and hide the data and of course, you can define a constructor. A great book that might help is The GLib/GTK+ Development Platform. In chapter 3 you can find a good introduction to Semi-Object-Oriented Programming in C.
Here is a possible implementation, not necessarily the best one:
/src/main.c
#include <stdio.h>
#include "point.h"
int main()
{
Point *p1 = init(6, 7);
printf("%d\n", getX(p1));
printf("%d\n", getY(p1));
Point *p2 = init(12, 14);
printf("%d\n", getX(p2));
printf("%d\n", getY(p2));
setX(p2, 16);
printf("%d\n", getX(p2));
setY(p2, 16); /* error; we want y to initialize once and remain constant. Also accessing y with p2->y is an error too. */
printf("%d\n", getY(p2)); /* getY is ok */
freep(p1);
freep(p2);
}
/src/point.h
typedef struct _Point Point;
Point *init(int, int);
int getX(Point *);
void setX(Point *, int);
int getY(Point *);
void freep(Point *);
/src/point.c
#include <stdlib.h>
#include "point.h"
struct _Point{
int x;
int y;
};
Point *init(int x, int y)
{
Point *temp;
temp = malloc(sizeof(Point));
temp->x = x;
temp->y = y;
return temp;
}
int getX(Point *p)
{
return p->x;
}
void setX(Point *p, int x)
{
p->x = x;
}
int getY(Point *p)
{
return p->y;
}
void freep(Point *p)
{
free(p);
}
Furthermore, if we need a private method in our class, we do not provide a declaration of it in the header and also we use static to restrict its access within the class's file.
I have two forward declared functions and a struct:
int _bar(void*);
int _bar2(int);
typedef struct foo {
void* array[128];
int (*bar)(void* x) = _bar;
int (*bar2)(int x) = _bar2;
} FOO;
How can array be accessed from bar and bar2 in an arbitrary instance of FOO, such that array is mutable by each function? Can it be done?
And yes, I know it's easier and arguably better to just use something other than C to do this kind of thing. That's simply not the point, so please answer the question as asked, without an attempt to 'diagnose' some deeper problem like many replies here do.
You are trying to do OOP in C. You want bar and foo to be like C++ member function. You can't do that in C and you should't even try. Don't fight the language.
Just add a Foo parameter to the free functions:
typedef struct foo {
void* array[128];
} Foo;
int bar(/*const*/ Foo* foo, void*);
int bar2(/*const*/ Foo* foo, int);
You could do something like this:
#include <stdio.h>
typedef struct foo {
int array[128];
int(*bar)(struct foo* this, void* x);
int(*bar2)(struct foo* this, int x);
} FOO;
int _bar(FOO *this, void *p)
{
printf("bar2(%p)\n", p);
return 0;
}
int _bar2(FOO *this, int i)
{
printf("array[4] = %d\n", this->array[4]);
printf("bar2(%d)\n", i);
return i*2;
}
void ConstructFoo(struct foo *f)
{
for (int i = 0; i < sizeof(f->array) / sizeof(f->array[0]); i++)
f->array[i] = i;
f->bar = _bar;
f->bar2 = _bar2;
}
int main()
{
struct foo f;
ConstructFoo(&f);
printf ("%d\n", f.bar2(&f, 42));
}
I modified the type of array just for makeing the example simpler.
This example can be enhanced further depending on what you actually need, for example you could add function that set the bar and bar2 "member" functions to something else than _bar and _bar2.
To explain more, I have two structures-'first' and 'second' having common variables 'jack' and 'jill'. I want to print jack via a pointer based on if-else condition.
I understand at the time of printing I have to typecast the void pointer. But whether the pointer points to struct a or b is decided on run time.
It is a basic C code. How to overcome this?
Code
#include <stdio.h>
int main(void)
{
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
a first;
b second;
void *z;
if(1)
{
a* z;
z = &first;
printf("First one");
}
else
{
b* z;
z = &second;
printf("Second one");
}
printf("%d\n", z->jack);
return 0;
}
Error
prog.c:36:17: warning: dereferencing 'void *' pointer printf("%d\n", z->jack); prog.c:36:17: error: request for member 'jack' in something not a structure or union
You get a compiler warning since the compiler does not understand z->jack since z is a void * (note that the declarations a* z and b* z are not valid outside the scope of the if and else block).
To overcome this you can use a function printJack as shown in the following listing:
#include <stdio.h>
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
void printJack(void *pStruct, int type)
{
switch (type)
{
case 1:
printf("jack: %d\n", ((a *)pStruct)->jack);
break;
default:
printf("jack: %d\n", ((b *)pStruct)->jack);
break;
}
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.jack = 5;
second.jack = 4892;
printJack(&first, 1);
printJack(&second, 0);
z = &first;
printJack(z, 1);
return (0);
}
I've written code like this often and experienced a lot of trouble with it. Not at the time of implementing, since you are knowing what you are typing at that moment but let's say a few years later if you need to extend your code. You will miss a few places where you cast from void * to a * or b * and you'll spend a lot of time debugging what's going on...
Now I'm writing things like this in the following way:
#include <stdio.h>
typedef struct header
{
int jack;
float jill;
} h;
typedef struct one
{
struct header header;
/* what ever you like */
}a;
typedef struct two
{
struct header header;
char something;
int something1;
/* and even more... */
}b;
void printJack(void *pStruct)
{
printf("jack: %d\n", ((struct header *)pStruct)->jack);
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.header.jack = 5;
second.header.jack = 4892;
printJack(&first);
printJack(&second);
v = &first;
printJack(v);
return (0);
}
As you've noticed I have declared a new struct header which covers the the common parts of struct one and struct two. Instead of casting the void * to either a * or b * a "common" cast to struct header * (or h *) is done.
By doing so you can easily extend the "common attribtues" of the structs or you can implement further structs using this header and function printJack still will work. Additionally there is no need for attribute type anymore making is easier to call printJack. You can even change the type of jack without needing to change it in various places within your code.
But remember that struct header needs to be the first element of the structs you use this mechanism. Otherwise you will end up with a few surprises since you are using memory which does not contain the data of the struct header...
I want to learn more about using function pointers in C structs as a way to emulate objects-oriented programming, but in my search, I've just found questions like this where the answer is simply to use a function pointer without describing how that would work.
My best guess is something like this
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create() {
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
But that give me compiler warnings warning: assignment from incompatible pointer type, so obviously I'm doing something wrong. Could someone please provide a small but complete example of how to use a function pointer in a C struct correctly?
My class taught in C does not even mention these. It makes me wonder whether these are actually used by C programmers. What are the advantages and disadvantages of using function pointers in C structs?
The answer given by Andy Stow Away fixes my compiler warning, but doesn't answer my second question. The comments to that answer given by eddieantonio and Niklas R answer my second question, but don't fix my compiler warning. So I'm pooling them together into one answer.
C is not object-oriented and attempting to emulate object-oriented design in C usually results in bad style. Duplicating methods called on structs so that they can be called using a pointer to the struct as I have in my example is no exception. (And frankly, it violates DRY.) Function pointers in structs are more useful for polymorphism. For example, if I had a struct vector that represented a generic container for a linear sequence of elements, it might be useful to store a comparison_func member that was a function pointer to allow sorting and searching through the vector. Each instance of the vector could use a different comparison function. However, in the case of a function that operates on the struct itself, it is better style to have a single separate function that is not duplicated in the struct.
This makes the answer to what is correct more complicated. Is what is correct how to make my above example compile? Is it how to reformat my above example so that it has good style? Or is it what is an example of a struct that uses a function pointer the way C programmer would do it? In formulating my question, I did not anticipate the answer being that my question was wrong. For completeness, I will provide an example of each answer to the question.
Fixing the Compiler Warning
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*, int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
Reformatting the Style
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
};
void my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
my_struct_set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
Demonstrating a Use for Function Pointer in Structs
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct
{
void* data;
int (*compare_func)(const void*, const void*);
};
int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
return m->compare_func(m->data, comparable);
}
struct my_struct* my_struct_create(void* initial_data,
int (*compare_func)(const void*, const void*))
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = initial_data;
result->compare_func = compare_func;
return result;
}
int int_compare(const void* a_pointer, const void* b_pointer)
{
return *(int*)a_pointer - *(int*) b_pointer;
}
int string_compare(const void* a_pointer, const void* b_pointer)
{
return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}
int main(int argc, const char* argv[])
{
int int_data = 42;
struct my_struct* int_comparator =
my_struct_create(&int_data, int_compare);
char* string_data = "Hello world";
struct my_struct* string_comparator =
my_struct_create(&string_data, string_compare);
int int_comparable = 42;
if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
{
printf("The two ints are equal.\n");
}
char* string_comparable = "Goodbye world";
if (my_struct_compare_to_data(string_comparator,
&string_comparable) > 0)
{
printf("The first string comes after the second.\n");
}
free(int_comparator);
free(string_comparator);
return 0;
}
In your struct definition, change it to
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*,int);
};
and now use the above function pointer in main as
thing->set_data(thing,1);
The solution consists of two parts, one is a static library that receives instances of struct from the user of the library. Library doesn't know what will be the type of structs, all it knows there will be two function pointers to it with a specific name.
Library Code
pre-compiled library has no way of knowing types of user structs, hence receiving via void*
void save(void *data) {
// library will save/cache user's object
data->registered(); // if register successful
}
void remove(void *data) {
// library will remove the object from memory
data->remove(); // if removed successful
}
User of the Library Code
struct Temp { // random order of fields
void (*custom1)();
void (*registered)();
void (*custom2)();
void (*remove)();
void (*custom3)();
}
void reg() {
printf("registered");
}
void rem() {
printf("removed");
}
void custom1() {}
void custom2() {}
void custom3() {}
var temp = malloc(struct Temp, sizeof(struct Temp));
temp->registered = reg;
temp->remove = rem;
temp->custom1 = custom1; // some custom functions
temp->custom2 = custom2;
temp->custom3 = custom3;
// calling library code
save(temp);
remove(temp);
Q. Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
No there is not.
Your best bet is to create a structure in the library that has these members, and pass that structure instead of void*.
As #immibis said, there is no way for this to work (i.e. no way for the compiler to justify compiling such code) if the compiler does not know what the types of the data being passed to the function are.
Since you wanted to pass the objects along to the library without storing information about the type of each object in the library, you can fake polymorphism in C, by doing the following:
callback.h
#ifndef _CALLBACK_H_
#define _CALLBACK_H_
typedef struct {
void (*registered)();
void (*removed)();
} ICallback;
#endif _CALLBACK_H_
pre_comp.h
#ifndef _PRE_COMP_H_
#define _PRE_COMP_H_
#include "callback.h"
void save(ICallback* data);
void remove(ICallback* data);
#endif /* _PRE_COMP_H_ */
precomp.c
#include <stdlib.h> /* NULL */
#include "callback.h"
#include "pre_comp.h"
void save(ICallback *data) {
if (NULL != data && NULL != data->registered) {
data->registered(); // if register successful
}
}
void remove(ICallback *data) {
if (NULL != data && NULL != data->removed) {
data->removed(); // if removed successful
}
}
main.c
#include <stdio.h>
#include "pre_comp.h"
#include "callback.h"
struct Temp {
ICallback base; // has to be defined first for this to work
void (*custom1)();
void (*custom2)();
void (*custom3)();
};
// calling library code
void reg() {
puts("registered");
}
void rem() {
puts("removed");
}
int main() {
struct Temp data = {{reg, rem}};
save((ICallback*)&data);
remove((ICallback*)&data);
}
compiling
gcc pre_comp.c main.c
output
registered
removed
If the library has 0 information about the possible struct types, then you
cannot do it. The library has to get somehow the information or the offsets.
The only way I can think of is:
All register member have the same prototype
Pass the offset to the function.
I created an example of this
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
// function that does not know anything about any struct
void reg(void *data, size_t offset)
{
uintptr_t *p = (uintptr_t*) (((char*) data) + offset);
void (*reg)() = (void(*)()) *p;
reg();
}
struct A {
int c;
void (*reg)();
};
struct B {
int b;
int c;
void (*reg)();
};
void reg_a()
{
printf("reg of A\n");
}
void reg_b()
{
printf("reg of B\n");
}
int main(void)
{
struct A a;
struct B b;
a.reg = reg_a;
b.reg = reg_b;
reg(&a, offsetof(struct A, reg));
reg(&b, offsetof(struct B, reg));
return 0;
}
This prints:
$ ./c
reg of A
reg of B
I run it with valgrind and I did not get any errors nor warnings. I'm not sure if
this violates somehow strict aliasing rules or yields undefined behaviour
because of the uintptr_t* conversions, but at least it seems to work.
I think however, the more cleaner solution is to rewrite the register (btw. register
is a keyword in C, you cannot use that for a function name) function to
accept a function pointer and possible parameters, something like this:
#include <stdio.h>
#include <stdarg.h>
void reg(void (*func)(va_list), int dummy, ...)
{
if(func == NULL)
return;
va_list ap;
va_start(ap, dummy);
func(ap);
va_end(ap);
}
void reg1(int a, int b)
{
printf("reg1, a=%d, b=%d\n", a, b);
}
void vreg1(va_list ap)
{
int a = va_arg(ap, int);
int b = va_arg(ap, int);
reg1(a, b);
}
void reg2(const char *text)
{
printf("reg2, %s\n", text);
}
void vreg2(va_list ap)
{
const char *text = va_arg(ap, const char*);
reg2(text);
}
int main(void)
{
reg(vreg1, 0, 3, 4);
reg(vreg2, 0, "Hello world");
return 0;
}
This has the output:
reg1, a=3, b=4
reg2, Hello world
Note that reg has a dummy parameter. I do that because the man page of
stdarg says:
man stdarg
va_start():
[...]
Because the address of this argument may be used in the va_start() macro,
it should not be declared as a register variable, or as a
function or an array type.
You can take an approach similar to qsort and pass function pointers in addition to a void pointer to the structure.
Here is the function prototype for qsort, which is a function that can be used to sort arrays of any type:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
It takes a function pointer that performs the comparison because without it qsort wouldn't know how to compare two objects.
This can be applied to your task with a function prototype like this:
int DoFoo(void *thing, void (*register)(void *), void (*remove)(void *))
This function takes a void pointer to your struct and then two functions that it can call when it needs to register or remove that struct. Having the functions be members of the struct is not required and I generally do not recommend it. I recommend reading up on qsort because it is does something similar to what you are trying to do.