Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a custom data type as a void pointer to a function

Tags:

c

pointers

void    do_something(void *data)
{
    t_my_type   *mt;
    
    mt = (t_my_type *)data;
    //mt->my_var = ...
    //...
}

void    do_something2(t_my_type *mt)
{
    //mt->my_var = ...
    //...
}

int main(void)
{
    t_my_type   mt;
    
    do_something(&mt);          // works (case 1)
    do_something((void *)&mt);  // works (case 2)

    do_something2(&mt);         // works (case 3)
}

Which one is recommended or NOT recommended and WHY?

All of the function calls do work, however, some people would suggest that case 2 should be used?

UPDATED QUESTION (since, my original one from above was a simplified version; I should have added more context to make it more specific):

If we take the below function definition ( from https://github.com/42paris/minilibx-linux ):

int mlx_loop_hook(t_xvar *xvar, int (*funct)(), void *param)
{
  xvar->loop_hook = funct;
  xvar->loop_param = param;
}

And, if I have my two functions as mentioned originally (with the slight change of returning int instead of void):

  1. int do_something(void *data) { /* ... */ } and
  2. int do_something2(t_my_type *mt) { /* ... */ }

Both can be passed to mlx_loop_hook:

mlx_loop_hook(some_xvar, do_something, &my_data); // will work, no error thrown (case 4)

and

mlx_loop_hook(some_xvar, do_something2, &my_data); // will work too, no error thrown (case 5)

In this example, is there any reason why NOT to use case 5?

like image 826
Atti Avatar asked Oct 20 '25 21:10

Atti


1 Answers

In such trivial example use the type your function is expecting. But if you write function which may handle many types of parameters you can use void * as parameter

Examples:

#include <stdio.h>

typedef enum
{
    INT, LONGINT, DOUBLE,
}data_type;

typedef struct
{
    data_type type;
    double val;
}double_type;

typedef struct
{
    data_type type;
    int val;
}int_type;

typedef struct
{
    data_type type;
    long int val;
}longint_type;


void print(const void *val)
{
    const double_type *dt = val;

    switch(dt -> type)
    {
        case INT:
            printf("%d\n", ((int_type *)val) -> val);
            break;
        case LONGINT:
            printf("%ld\n", ((longint_type *)val) -> val);
            break;
        case DOUBLE:
            printf("%f\n", dt -> val);
            break;
    }
}

void print2(const data_type type, const void *val)
{
    switch(type)
    {
        case INT:
            printf("%d\n", *(const int *)val);
            break;
        case LONGINT:
            printf("%ld\n", *(const long int *)val);
            break;
        case DOUBLE:
            printf("%f\n", *(const double *)val);
            break;
    }
}


int main(void)
{
    print(&(int_type){.type = INT, .val = INT_MAX});
    print(&(longint_type){.type = LONGINT, .val = LONG_MAX});
    print(&(double_type){.type = DOUBLE, .val = 456.89067});

    int i = 567;
    long l = 5678;
    double d = 45678.90;

    print2(INT, &i);
    print2(LONGINT, &l);
    print2(DOUBLE, &d);
}

some people would suggest that case 2 should be used?

They probably are using C++ compiler to compile C language code thich is not correct as C++ and C are different languages.

In C language you do not need to cast any type to void * and vice versa, in C++ you do

like image 93
0___________ Avatar answered Oct 23 '25 10:10

0___________



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!