What Does "Void *(*)(Void *)" Mean in C++

What does void mean in C, C++, and C#?

Basically it means "nothing" or "no type"

There are 3 basic ways that void is used:

  1. Function argument: int myFunc(void)
    -- the function takes nothing.

  2. Function return value: void myFunc(int)
    -- the function returns nothing

  3. Generic data pointer: void* data
    -- 'data' is a pointer to data of unknown type, and cannot be dereferenced

Note: the void in a function argument is optional in C++, so int myFunc() is exactly the same as int myFunc(void), and it is left out completely in C#. It is always required for a return value.

What does (void**) mean in C?

It's a cast to a pointer to a void pointer.

You see this quite often with functions like CoCreateInstance() on Windows systems.

ISomeInterface* ifaceptr = 0;
HRESULT hr = ::CoCreateInstance(CLSID_SomeImplementation, NULL, CLSCTX_ALL,
IID_ISomeInterface, (void**)&ifaceptr);
if(SUCCEEDED(hr))
{
ifaceptr->DoSomething();
}

The cast converts the pointer to an ISomeInterface pointer into a pointer to a void pointer so that CoCreateInstance() can set ifaceptr to a valid value.

Since it is a pointer to a void pointer, the function can output pointers of any type, depending on the interface ID (such as IID_ISomeInterface).

Is it better to use C void arguments void foo(void) or not void foo()?

void foo(void);

That is the correct way to say "no parameters" in C, and it also works in C++.

But:

void foo();

Means different things in C and C++! In C it means "could take any number of parameters of unknown types", and in C++ it means the same as foo(void).

Variable argument list functions are inherently un-typesafe and should be avoided where possible.

When to use const void*?

const int *var;

const is a contract. By receiving a const int * parameter, you "tell" the caller that you (the called function) will not modify the objects the pointer points to.

Your second example explicitly breaks that contract by casting away the const qualifier and then modifying the object pointed by the received pointer. Never ever do this.

This "contract" is enforced by the compiler. *dummy = 1 won't compile. The cast is a way to bypass that, by telling the compiler that you really know what you are doing and to let you do it. Unfortunately the "I really know what I am doing" is usually not the case.

const can also be used by compiler to perform optimization it couldn't otherwise.


Undefined Behavior note:

Please note that while the cast itself is technically legal, modifying a value declared as const is Undefined Behavior. So technically, the original function is ok, as long as the pointer passed to it points to data declared mutable. Else it is Undefined Behavior.

more about this at the end of the post


As for motivation and use lets take the arguments of strcpy and memcpy functions:

char* strcpy( char* dest, const char* src );
void* memcpy( void* dest, const void* src, std::size_t count );

strcpy operates on char strings, memcpy operates on generic data. While I use strcpy as example, the following discussion is exactly the same for both, but with char * and const char * for strcpy and void * and const void * for memcpy:

dest is char * because in the buffer dest the function will put the copy. The function will modify the contents of this buffer, thus it is not const.

src is const char * because the function only reads the contents of the buffer src. It doesn't modify it.

Only by looking at the declaration of the function, a caller can assert all the above. By contract strcpy will not modify the content of the second buffer passed as argument.


const and void are orthogonal. That is all the discussion above about const applies to any type (int, char, void, ...)

void * is used in C for "generic" data.


Even more on Undefined Behavior:

Case 1:

int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object

*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable

Case 2:

const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.

I began with these examples because they are easier to understand. From here there is only one step to function arguments:

void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}

Case 1:

int a = 0;
foo(&a); // the write inside foo is legal

Case 2:

int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior

Again I must emphasize: unless you really know what you are doing, and all the people working in the present and in the future on the code are experts and understand this, and you have a good motivation, unless all the above are met, never cast away the constness!!

What does void* mean and how to use it?

A pointer to void is a "generic" pointer type. A void * can be converted to any other pointer type without an explicit cast. You cannot dereference a void * or do pointer arithmetic with it; you must convert it to a pointer to a complete data type first.

void * is often used in places where you need to be able to work with different pointer types in the same code. One commonly cited example is the library function qsort:

void qsort(void *base, size_t nmemb, size_t size, 
int (*compar)(const void *, const void *));

base is the address of an array, nmemb is the number of elements in the array, size is the size of each element, and compar is a pointer to a function that compares two elements of the array. It gets called like so:

int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);

The array expressions iArr, dArr, and lArr are implicitly converted from array types to pointer types in the function call, and each is implicitly converted from "pointer to int/double/long" to "pointer to void".

The comparison functions would look something like:

int compareInt(const void *lhs, const void *rhs)
{
const int *x = lhs; // convert void * to int * by assignment
const int *y = rhs;

if (*x > *y) return 1;
if (*x == *y) return 0;
return -1;
}

By accepting void *, qsort can work with arrays of any type.

The disadvantage of using void * is that you throw type safety out the window and into oncoming traffic. There's nothing to protect you from using the wrong comparison routine:

qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);

compareInt is expecting its arguments to be pointing to ints, but is actually working with doubles. There's no way to catch this problem at compile time; you'll just wind up with a missorted array.

cannot convert '*void(MyClass::*)(void*) to void*(*)(void*) in pthread_create function

I don't want to declare dequeueLoop as a static function

If you want to use pthreads, then you'll need a static or non-member function for the entry point. You can pass a pointer to your object to this function, using it as a trampoline into the non-static member function:

static void * dequeueEntry(void * self) {
return static_cast<CameraManager*>(self)->dequeueLoop();
}

dequeueThreadId = pthread_create(
&dequeueThread, NULL,
&CameraManager::dequeueEntry, // <-- pointer to trampoline function
this); // <-- pointer to object for member function

Alternatively, if you have a modern compiler, you could use the standard thread library instead:

std::thread thread(&CameraManager::dequeLoop, this);


Related Topics



Leave a reply



Submit