0
votes

I am getting my head around void pointers in C++ and as an exercise have written the following code:

void* routine(void* number){

    int n = (int)number;
    int* np = (int*)number;

    cout<<"void pointer: "<<number<<endl; 
    cout<<"casted int pointer: "<<np<<endl; 
    cout<<"int pointer content: "<<*np<<endl; 


    return (void*)NULL;
}

int  main(){
    int num = 1;
    routine((void*)num);
}

This breaks in runtime as the pointer np, casted from void* to int* is dereferenced.

I attempt to pass the argument number as a void pointer and dereference its value inside the function. Arithmetic on void pointers are illegal, therefore what I try to do is cast the pointer to an int* and attempt to dereference this casted copy.

I somewhat expect this not to work, but if that were the case I would also expect some sort of compiler error as is the case when this attempt is made without the int* cast. The reason I sort of expect it to work is that the casted pointer retains the original void pointer address, meaning that after the cast it appears to be just a regular memory address, which I see no reason to be inaccessible by regular dereference. The n variable is a copy of the referenced value, but is just that - I cannot change the actual value in the memory address.

Is this possible with a void pointer? What am I missing?

2
routine(&num)? - IlCapitano
"I somewhat expect this not to work, but if that were the case I would also expect some sort of compiler error" - When you force casts like these you're taking away a lot of control from the compiler and effectively telling it 'trust me, I know what I'm doing'. So then if you cast wrong, the problem is all on you. - TheUndeadFish
"I am getting my head around void pointers in C++" Might I ask why? Most people should never need to use them. But yes, you did a bad cast from the value 1 instead of its address, so I VTC as a typo. - underscore_d
Re. "learning phtreads which require the void pass": use std::thread instead if at all possible. - G.M.
C does allow you to convert integers to pointers and pointers to integers, although there is no guarantee you'll end up with the same value because the conversions are implementation defined. It'll probably work fine. You could use intptr_t instead of int, but even that is not guaranteed to work. (The round trip from void * to intptr_t to void * is guaranteed to end up pointing to the same thing as the initial pointer, but the round trip from intptr_t to void * to intptr_t is not guaranteed to end up with the initial numeric value.) - Ian Abbott

2 Answers

2
votes

The usual &num will do.

routine(&num);

Any object pointer implicitly converts to void*. On the callback function you'll have to convert it back to the correct pointer type (use static_cast not C-style cast, that will prevent you from accidentally mixing up pointers containing addresses with integer values that are not memory addresses).

void* routine( void* user_ptr )
{
    int* np = static_cast<int*>(user_ptr);

Other pointers which aren't object pointers won't implicitly convert to void*, including function pointers and pointer-to-members. Adding a cast will force the compiler to do the wrong thing and be quiet about it, but (apart from the return value of dlsym() or its Windows equivalent GetProcAddress()) it isn't safe to mix void* with these other pointer varieties anyway.

0
votes
void* routine(void* number){

    int n = (int)number;
    int* np = (int*)number;

    cout<<"void pointer: "<<number<<endl; 
    cout<<"casted int pointer: "<<np<<endl; 
    cout<<"int pointer content: "<<*np<<endl; 


    return (void*)NULL;
}


int  main(){
    int num = 1;
    int* num_p = &num;
    routine((void*)num_p);
}

Pointing to nums address before passing does the trick. The casting of an integer to a void pointer makes no sense.