Passing a struct into a generic function in C - c

I declare a new struct with the name of "Struct"
I have a generic function that takes in an argument "void *data".
void Foo(void *data)
I pass an instance of "Struct" into the generic function.
Struct s;
Foo(&s);
I want to access one of the properties of the struct in the function.
void Foo(void *data) {
char *word = (char*) data.word;
}
It's not allowed because it doesn't recognize data as a valid struct.
I even try to declare the data as the struct type first, and I get an error.
void Foo(void *data) {
Struct s = (Struct) data;
char *word = s.word;
}
I get "conversion to non-scalar type requested".

First of all, you should turn on your compiler's warning flags (all of them). Then you should pass a pointer to your Struct and use something other than struct as a variable name:
Struct s;
Foo(&s);
Then, in Foo:
void Foo(void *data) {
Struct *s = data;
char *word = s->word;
}
You can't convert non-pointer types to and from void* like you're trying to, converting pointer types to and from void* is, on the other hand, valid.

You need to pass a pointer to you struct and get a pointer to the struct inside the function:
Struct struct;
Foo(&struct);
void Foo(void *data) {
Struct* struct = (Struct*) data;
char *word = struct->word;
}

You have to use -> operator when requesting structure member via pointer.
This should work: char *word = (char*) data->word;
You also have to pass the address of the structure to the function. Like this: Foo(&struct);.

Firstly you need to call the function correctly:
Struct s;
Foo(&s);
Notice you're now passing a pointer to the structure.
Now, the function has to know that you're using a Struct (as opposed to something else) - perhaps because of another parameter, or a global variable, or some other reason. Then inside the function you can do:
void Foo(void *data) {
Struct *structpointer = p; /* Note - no need for a cast here */
/* (determine whether data does refer to a pointer then...) */
char *word = structpointer->word;
/* ... then use 'word'... */
}

Data is pointer, so whatever you cast it to must also be a pointer. If you said Struct* myStruct = (Struct*) data, all would be well with the world.

You are mixing pointers and data.
Struct struct defines a data object
void *data expects data to be a pointer.
Call Foo with a pointer to a Struct, and make other necessary changes

Struct struct;
Foo((void*)&struct);
void Foo(void *data) {
Struct *struct = (Struct*)data;
char *word = struct->word;
}
or the more compact form:
Struct struct;
Foo((void*)&struct);
void Foo(void *data) {
char *word = ((Struct*)data)->word;
}

Related

Using a function from a function array stored in a struct in C

I declared a struct like this one :
typedef struct s_data {
char buff[2048];
int len;
void *func[10];
struct data *next;
} t_data;
In my code, when passing a *data, I assigned some functions (just giving one so it is more understandable)
void init_data(t_data *data)
{
data->len = 0;
data->func[0] = &myfirstfunctions;
//doing the same for 9 others
}
My first function would be something taking as argument *data, and an int.
Then, I try to use this function in another function, doing
data->func[0](data, var);
I tried this and a couple of other syntaxes involving trying to adress (*func[0]) but none of them work. I kind of understood from other much more complex questions over there that I shouldn't store my function like this, or should cast it in another typedef, but I did not really understand everything as I am kind of new in programming.
void* can only be used reliably as a generic object pointer ("pointer to variables"). Not as a generic function pointer.
You can however convert between different function pointer types safely, as long as you only call the actual function with the correct type. So it is possible to do just use any function pointer type as the generic one, like this:
void (*func[10])(void);
...
func[0] = ((void)(*)(void))&myfirstfunction;
...
((whatever)func[0]) (arguments); // call the function
As you might note, the function pointer syntax in C is horrible. So I'd recommend using typedefs:
typedef void genfunc_t (void);
typedef int somefunc_t (whatever*); // assuming this is the type of myfirstfunction
Then the code turns far easier to read and write:
genfunc_t* func [10];
...
func[0] = (genfunc_t*)&myfirstfunction;
...
((somefunc_t*)func[0]) (arguments);
If all of your functions will have the same signature, you can do this like:
#include <stdio.h>
typedef void (*func)(void *, int);
struct s_data {
char buff[2048];
int len;
func f[10];
struct s_data *next;
};
static void
my_first_function(void *d, int x)
{
(void)d;
printf("%d\n", x + 2);
}
static void
init_data(struct s_data *data)
{
data->len = 1;
data->f[0] = my_first_function;
}
int
main(void)
{
struct s_data d;
init_data(&d);
d.f[0](NULL, 5);
return 0;
}
If your functions have different signatures, you will want to either use a union, or perhaps you will need several different members of the struct to store the function pointers.
The problem is that you haven't actually declared an array of function pointers. What you actually did is an array of pointers to void.
The syntax of declaring a pointer to function is as following:
function_return_type (*pointer_name)(arg1_type,arg2_type,...);
Then you can create an array of pointers to functions:
function_return_type (*arr_name[])(arg1_type, arg2_type,...)
Therefore, the declaration of your structure should look like this:
typedef void (*pointer_to_function)(void *, int);
struct s_data {
char buff[2048];
int len;
pointer_to_function array_of_pointeters[10];
struct s_data *next;
};
Good luck:)

how to control struct member behavior with struct const pointer as function parameter?

I have a C code, somewhat similar to this:
struct st
{
int *var;
}
void fun(st *const ptr)
{
// considering memory for struct is already initialized properly.
ptr->var = NULL; // NO_ERROR
ptr = NULL; // ERROR, since its a const pointer.
}
void main()
{
//considering memory for struct is initialized properly
fun(ptr);
}
I dont want to declare int *var as const in the structure definition, so as not to mess with the huge code base. Not looking to make any change in the structure definition
Is there any way in C, to get an error for the NO_ERROR line
ptr->var = NULL; // NO_ERROR ?
Just declare the parameter with const, so the ptr is a pointer to a const object:
void fun(const struct st* ptr)
Your declaration makes ptr to be constant, but not the object to which it points. Also don't miss struct keyword
void fun(struct st *const ptr);
Instead you should use
void fun(const struct st *ptr);
Such declaration allows to change pointer but not the object to which it points.
Keep this in mind:
With type* const ptr, you cannot change the pointer but you can change the pointed data
With const type* ptr, you can change the pointer but you cannot change the pointed data
So all you need is to replace struct st* const ptr with const struct st* ptr.
Superb! Thank you so much guys!
I did this -
void fun(const struct st *const ptr);
and I was able to get an error while changing both ptr and ptr->var .. Just what I needed..

C void Pointer on mainframe

I'm currently working on modifying a dump program, but I can't figure out how to properly navigate with a void pointer. Below is the function that I'm working in, and the instruction that I'm trying to execute. I've tried casting mem to a struct, but I'm not sure of the sytnax and I keep getting an error. For the code below, the specific error I'm getting is:
47 | mem = mem->tcbtio
===========> .........a..............................................
*=ERROR===========> a - CCN3122 Expecting pointer to struct or union.
Here is my function:
void hexdump(void *mem, unsigned int len)
{
mem = mem->tcbtio;
...
}
Here are my struct defintions:
struct psa {
char psastuff[540];
struct tcb *psatold;
char filler[4];
struct ascb *psaaold;
};
struct tcb {
struct prb *tcbrb;
char tcbstuff[8];
struct tiot *tcbtio;
};
struct tiot {
char tiocnjob[8];
char tiocpstn[8];
char tiocjstn[8];
};
I need to keep it as a void pointer, as I need to cast it to char and int later on in the function.
It seems as you are expecting to find a tcb struct, starting at the address pointed by mem, but the aim of the code is obscure and the question not clear.
If this is really the case, you can try this:
mem = ((struct tcb *)mem)->tcbtio;
You cannot dereference a void pointer. You can think it this way if you have a void pointer, how will compiler know what type of address it is holding. And by doing mem = mem->tcbtio how much offset it has to make.
Modify your function as:
void hexdump(void *mem, unsigned int len)
{
struct tcbtio *mem2;
mem2 = ((struct tcb*) mem) -> tcbtio;
...
// Use mem2 later
}

function prototype with void* parameter

I have two functions, each taking a pointer to a different type:
void processA(A *);
void processB(B *);
Is there a function pointer type that would be able to hold a pointer to either function without casting?
I tried to use
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
but it didn't work (compiler complains about incompatible pointer initialization).
Edit: Another part of code would iterate through the entries of Ps, without knowing the types. This code would be passing a char* as a parameter. Like this:
Ps[i](data_pointers[j]);
Edit: Thanks everyone. In the end, I will probably use something like this:
void processA(void*);
void processB(void*);
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
...
void processA(void *arg)
{
A *data = arg;
...
}
If you typedef void (*processor_t)(); then this will compile in C. This is because an empty argument list leaves the number and types of arguments to a function unspecified, so this typedef just defines a type which is "pointer to function returning void, taking an unspecified number of arguments of unspecified type."
Edit: Incidentally, you don't need the ampersands in front of the function names in the initializer list. In C, a function name in that context decays to a pointer to the function.
It works if you cast them
processor_t Ps[] = {(processor_t)processA, (processor_t)processB};
By the way, if your code is ridden with this type of things and switch's all over the place to figure out which function you need to call, you might want to take a look at object oriented programming. I personally don't like it much (especially C++...), but it does make a good job removing this kind of code with virtual inheritance.
This can be done without casts by using a union:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef union { void (*A)(A *); void (*B)(B *); } U;
U Ps[] = { {.A = processA}, {.B = processB} };
int main(void)
{
Ps[0].A(0); // 0 used for example; normally you would supply a pointer to an A.
Ps[1].B(0); // 0 used for example; normally you would supply a pointer to a B.
return 0;
}
You must call the function using the correct member name; this method only allows you to store one pointer or the other in each array element, not to perform weird function aliasing.
Another alternative is to use proxy functions that do have the type needed when calling with a parameter that is a pointer to char and that call the actual function with its proper type:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef void (*processor_t)();
void processAproxy(char *A) { processA(A); }
void processBproxy(char *B) { processB(B); }
processor_t Ps[] = { processAproxy, processBproxy };
int main(void)
{
char *a = (char *) address of some A object;
char *b = (char *) address of some B object;
Ps[0](a);
Ps[1](b);
return 0;
}
I used char * above since you stated you are using it, but I would generally prefer void *.

Casting a void pointer to a struct

I started feeling comfortable with C and then I ran into type casting. If I have the following defined in an *.h file
struct data {
int value;
char *label;
};
and this in another *.h file
# define TYPE void*
How do I cast the void pointer to the struct so that I can use a variable "TYPE val" that's passed into functions? For example, if I want to utilize the value that TYPE val points to, how do I cast it so that I can pass that value to another functions?
(struct data*)pointer
will cast a pointer to void to a pointer to struct data.
Typecasting void pointer to a struct can be done in following
void *vptr;
typedef struct data
{
/* members */
} tdata;
for this we can typecast to struct
lets say u want to send this vptr as structure variable to some function
then
void function (tdata *);
main ()
{
/* here is your function which needs structure pointer
type casting void pointer to struct */
function((tdata *) vptr);
}
Note: we can typecast void pointer to any type, thats the main purpose of void pointers.

Resources