Usage of void in C

Three patterns when using "void" keyword in C

Going into some USB programming for a project I am into (on my Mac), I ran into this and I thought would be nice and useful to elaborate a bit. This is about void* pointers and callbacks in C. USB device discovery and probing under IOKit makes heavy use of callbacks, I wanted to write it down, for future reference. Or read more about it here.

Bottom-line, I have always taken void to mean absent. Here are three cases in C that matches to this use of absent. Last but not least, I’ll make some comments on C callbacks.

Case 1: Return value is absent

A function is a set of operations that return something. However, in C anything is a function and, since a function has to return something, when this does not happen, the “void” comes handy. Practically, you mark a void function as being… not a function:

void TestingVoid(int param)
{
    printf("testing void return with %d param.\n", param);
}

Case 2: Function parameters are absent

A void–parameter function can return something:

int ReturnSomething(void)
{
    int result = 1 + 1;
    printf("Void parameter, but returning something: %i", result);
    return result;
}

Well obviously a function with void parameters is not too useful, unless you pass a void pointer.

Case 3: Type of what is pointed to is absent

int ReturnSomethingFromVoid(void *ptr)
{
    int result;
    result = ptr;
    printf("Void parameter pointer, but returning an integer: %d", (int)ptr);
    return result;
}

The void pointer, also known as the generic pointer, is a special type of pointer that can be pointed at objects of any data type. A void pointer is declared like a normal pointer, using the void keyword as the pointer’s type. It is extremely useful in situations when the return type is not known or not defined, or is awaited to be defined at run-time or in cases when code selects a function to execute based on run-time values. The latter case is covered by function pointers (see below).

However, since void indicates absence of type, in C language it is not possible to dereference the void pointer without prior type-casting.

When you build the code above, the compiler will complain that there is an incompatible pointer to integer conversion:

Casting is done explicitly (see lines 4 and 5 below):

int ReturnSomethingElseFromVoid(void *ptr)
{
    int result;
    result = *((UInt32*)ptr);
    printf("Void parameter pointer only: %d\n", (*(UInt32*)ptr));
    printf("Void parameter variable only: %d\n", result);
    return result;
}

Running this in main():

int main(int argc, const char * argv[])
{
    /* initialize function pointer to my_callback */
    void *something = NULL;
    UInt32 addition = 235;
    something = &addition;

    ReturnSomethingElseFromVoid(something);

    return 0;
}

Results in console are:

Void parameter pointer only: 235
Void parameter variable only: 235
Program ended with exit code: 0

Function pointers

Consider the following prototype:

int (*ptrFunction)(int, int);

This is a function pointer. Instead of referring to data values, a function pointer points to executable code within memory. When dereferenced, a function pointer can be used to invoke the function it points to and pass it arguments just like a normal function call. Such an invocation is also known as an “indirect” call, because the function is being invoked indirectly through a variable instead of directly through a fixed name or address. Function pointers can be used to simplify code by providing a simple way to select a function to execute based on run-time values.

Similar to data pointers, when you work with function pointers you are working (mainly) with memory location (that function pointers point to). Thus, to have a working code, you have to instruct the function pointer to point to a valid function address (see line 9, below):

int func(int, int); // prototype of function to be pointed to by the function pointer -> mandatory

int main(int argc, const char * argv[])
{
    /* declaring a pointer to a function which takes to int arguments and returns an integer as result */
    int (*ptrFunction)(int, int);

    /* the assignment of pointer function ptrFunction to func address is mandatory: */
    ptrFunction = func;

    .... // other stuff

    return 0;
}

/* implementation of function to be pointer to by the function pointer */
int func(int x, int y)
{
    return x + y;
}

A working example of the above could be something like:

#include

int func(int, int);

int main(int argc, const char * argv[])
{
    int result1, result2 = 22;

    /* declaring a pointer to a function which takes to int arguments and returns an integer as result */
    int (*ptrFunction)(int, int);

    /* assign ptrFunction to func address */
    ptrFunction = func;

    /* calling func() thorugh explicit dereference */
    result1 = (*ptrFunction)(10, 20);

    /* calling func() through implicit dereference */
    // --> not allowed in C99
    //result2 = ptrFunc(10, 20);

    printf("result1 = %d result2 = %d\n", result1, result2);

    return 0;
}

int func(int x, int y)
{
    return x + y;
}

Which will generate:

result_1 = 30 result_2 = 22
Program ended with exit code: 0

That’s it for today. Next time I will dive into C callbacks.

 
 
Filed in C stuff and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *