Home > front end >  In plain C, how to assign a void pointer value to a double
In plain C, how to assign a void pointer value to a double

Time:03-05

void foo(void* p) {
    double d = (double) p; // Doesn’t compile.
    printf(“%f\n”, d);
}

What I need is to be able to call

foo((void*) 13.0);

and have 13.0 printed.

Note

I need this in order to store distances (of type double) between source nodes and arbitrary nodes stored in a C hash map that is “void*” generic in graph search. See https://github.com/coderodde/BidirectionalDijkstra4Perl2

CodePudding user response:

The standard way has been given by Eric's answer.

But if the size of a void * is not smaller than the size of a double, you can store the representation of the double in a void *. From that point you cannot use the pointer for anything but extracting back the representation to a double object. Here is an example code demonstrating it:

#include <stdio.h>    
#include <assert.h>
#include <memory.h>

void foo(void* p) {
    double d;
    memcpy(&d, &p, sizeof(d));
    printf(" % f\n", d);
}

int main() {
    void* p;
    // ensure that the representation of a double can fit in a void *
    static_assert(sizeof(void*) >= sizeof(double), "sizeof(double) > sizeof(void *)");
    double d = 13.0;
    memcpy(&p, &d, sizeof(d));
    foo(p);
    return 0;
}

But beware: this should only be used as a workaround to cope with legacy code. The portability is limited to platforms where the size of a double is not greater than the size of a void * which is false on a 32 bits platform. Compiling above code in 32 bits mode raises a compilation error:

error ...: sizeof(double) > sizeof(void *)

CodePudding user response:

When specification has a means of providing data through void *, the way you are usually intended to use it is to allocate memory for the data and pass the address of the memory as a void *. Then the software that receives the data converts the void * to a pointer to the appropriate type and uses that pointer to access the data in memory.

Thus, if you just need a single double value, a way you would do this is:

double *p = malloc(sizeof *p);  // Allocate memory for the data.
if (!p)  // Guard against allocation failure.
{
    fprintf(stderr, "Error, unable to allocate memory.\n");
    exit(EXIT_FAILURE);
}
*p = 13.0;  // Store data in memory.
foo(p);     // Pass the address of the data to foo.

Later, in some routine that was given the address of the data, you would do something like this:

void MyCallBackRoutine(void *vp) // Might be "const void *" instead.
{
    double *p = vp;  // Convert to "double *".  Might need "const" with it.
    printf("The conveyed data is %g.\n", *p);
}

You should also free the memory when it is no longer needed.

If you need more than just a double or other single item, you would create a struct containing all the members you needed and put all the data into it.

  • Related