ryyker
ryyker

Reputation: 23226

Method to pass double to void * argument

My question is driven by the need to correctly pass a double variable via a void * function argument. I ask because on my machine sizeof(void *) is 4, and sizeof(double) is 8, casting one to the other seems like it should result in a problem, but my compiler (CLANG, with ALL warnings on.) gives no indication of a problem, and the code seems to work fine.

Note that I have seen this, and this. They have similar component words in their titles, but do not answer this specific question.

Would the following lead to a strict aliasing violation error?, or undefined behavior?

// some calling function
double a = 0.000234423;
func1(&a);

...

void func1(void *var)
{
    double a = *(double *)(var);
}

Upvotes: 1

Views: 861

Answers (3)

4386427
4386427

Reputation: 44329

The size of a pointer has nothing to do with the size of the element it points to!

A 4 byte pointer can without problem point to an element which is 8 bytes or 32 bytes or whatever size.

I ask because on my machine sizeof(void *) is 4, and sizeof(double) is 8, casting one to the other seems like it should result in a problem

Well, if you did cast a 4 byte pointer to an 8 byte double, it would be a major problem. However, that is not what your code is doing.

This is what the code is doing:

double a = * (double *)(var);
           | \--------------/
           |  This casts a void pointer to a double pointer
           |
           --> This dereferences the double pointer, i.e. reads the value of the pointed
               to element (aka the pointed to double)

As the void pointer was created from the address of a double, it's perfectly legal to cast it back to a double pointer and perfectly legal to read the value of the pointed to element. In other words - during the function call you have an implicit cast of a double pointer to void pointer and inside the function the void pointer is casted back to double pointer. Perfectly legal C code.

With an extra step your code is equivalent to:

void func1(void *var)
{
    double *pd = (double *)var;
    double a = *pd;
}

which makes it a bit more clear.

Upvotes: 8

supercat
supercat

Reputation: 81217

If a function that receives an argument of type void* needs to receive a double value, one can define a structure, function, and macro:

struct doubleWrapper { double d[1]; };
struct doubleWrapper doWrapDouble(double d)
{      
  return (struct doubleWrapper){d};
}
#define wrapDouble(x) (doWrapDouble((x)).d)

and then use that function at call sites that need to pass a double value:

void functionTakingVoid(int mode, void *param)
{
  if (mode==0)
  {
    double myDouble = *(double*)param;
    ...
  }
}

void passDoubleToFunctionTakingVoid(double myValue)
{
  functionTakingVoid(0, wrapDouble(myValue));
}

Under C99, wrapDouble macro will return a pointer to a double whose lifetime will extend through the evaluation of the enclosing full expression, including function calls made thereby.

Upvotes: 1

MSalters
MSalters

Reputation: 179991

The normal solution is indeed to pass the address of the double variable, so a double*. That has a size that's no bigger than a void*.

Upvotes: 4

Related Questions