简体   繁体   中英

C Void pointer question

I have grep function in C( embedded programming ) that takes a void pointer as a parameter. the function needs to be able to handle different kinds of types of variables like chars ints and longs. How can I code the function so it can figure out by itself what type of variable i am passing ?? I dont know if this is possible. thanks

ie.


void grep( void *t ) 
{ 
   if( t == char ) 
   { 
      do this 
   } 
   if( t == int ) 
   { 
      do that  
   }  
   ... 
}

It is not possible to do with any accuracy. A 4 byte integer could easily be interpreted as a string for example. For example, a null terminated string "ABC" would be the same as the integer value 1094861568 (depending on byte order).

Void pointer contains just a location in memory where the piece of data is stored. You can't infer any type information from it. But what you can do is, pass two parameters to your function one for the type and another for the pointer.

If you can use C++ you can create a set of overloaded helper functions that will supply the type information.

That is not possible in C. You will have to indicate the intended type of the parameter explicitly. You will have to pass a second argument or pass a union or struct which has the type information as parameter.

You're basically asking how to do introspection in C. Unfortunately this is not a supported feature.

Instead you could use functions like grep_char as @anand.arumug pointed out. Or (if possible) you could move to C++ and make use of its function overloading features.

Direct answer: it's not possible. Also, you should avoid writing such super functions that act on multiple types 2unless you can truly generalize the code and apply polymorphism. In C, that would often involve function pointers. Otherwise, there's nothing wrong with writing multiple functions that each act on a single type. In fact, that should be preferable over super functions.

Here's a basic example (not very useful, but simple):

#include <stdio.h>

typedef int less_function(void*, void*);

struct foo
{
    int data;
};

int foo_less(void* a, void* b)
{
    struct foo* f1 = a;
    struct foo* f2 = b;
    return f1->data < f2->data;
}

int find(void* search_array, void* element, int num, int element_size, less_function* less)
{
    int j = 0;
    char* search_pos = search_array;

    for (j=0; j < num; ++j, search_pos += element_size)
    {
        // if current element == element to find
        if (!less(search_pos, element) && !less(element, search_pos) )
            return j;
    }
    return -1;
}

int main()
{
    struct foo my_array[10] = { {0}, {1}, {2}, {3}, {4}, {5}, {6}, {123}, {7}, {8} };
    struct foo search_element = {123};

    // outputs 7
    printf("%d\n", find(my_array, &search_element, 10, sizeof(struct foo), foo_less) );
}

In the above code, you can see that I don't have code like: if this type is an integer, do this, if it's a float, do that, if it's a struct foo object, do this, etc. Instead we rely on function pointers to provide the custom behavior for comparing the type of object being passed in.

qsort also does this and is a good example to look at. It's quite similar to the find function above, except its comparator doesn't simply return true/false based on whether the first object is less than the other: it's like strcmp and returns 0, -1, or +1.

I think you'll find this is not possible in C.

C++ has templates and overloading which are a nice solution to this sort of problem.

In plain old C you would simply write a different function for each type you need to handle.

Macros are another option in C, but consider whether its is worth the effort and confusion it may cause other developers.

You may want to take a look at the ioctl() function. It takes a generic pointer to memory and interprets it differently based on the request code passed to the function. You can't determine what a generic pointer points to without some sort of additional information, and the ioctl() function shows you one (relatively simple) way of doing it.

The only way i can think of is to either pass the type as a second parameter, or have a struct with the pointer and an enum or something specifying the type, and pass that instead of a naked pointer. C doesn't have built in metadata like .net and Java do, or even an equivalent to RTTI that i'm aware of.

This kind of multi-role function is not a recommended approach as it's hard to catch programming errors and debug. I suggest making separate grep functions for each argument type and have these call helper functions for any shared grep code logic.

If you must pass around typeless objects to functions then I suggest you wrap them in a struct which adorns them with a type. Something like:

struct {
    enum TYPE { INT, CHAR, STRING } type;
    void *object;
}

No its not possible.

You have to pass a additional variable to tell the function the type of input variable. However I think you can use the macro which is suggested above. This way you will break the function grep into 3 sub-functions (if I may call them that).

Enums will be easier in case you pass any other datatype later. You can use a switch statement inside the function and perform the operations on the input data.

enum TYPE( TYPE_1, TYPE_2, TYPE_3,TYPE_MAX}; /*Add other data types into this enum if need be */

Please name the enum entries as per your requirement.

Later you can just modify the function switch case and add a additional case to it.

If you know the types that you will be handling before hand, then you can define a grep function for each type like:

grep_int(int* pi);
grep_char(char* pc);
grep_float(float* pf);

Also define a macro like

#define GREP(T, TPTR_VAR) grep_##(TPTR_VAR)

So a call like GREP(int, pi) will get translated to grep_int(pi)

As Mark points out, it's not possible, but you could make overloaded versions for the types you're expecting.

Edit: Correction, you could create similar functions to handle the different types:

void grep_c( char *t ) 
{ 
    do this 
}

void grep_i( int *t ) 
{ 
    do that  
}

I've been writing too much C++ recently!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM