Method to pass double to void * argument

白昼怎懂夜的黑 提交于 2020-01-23 16:42:46

问题


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);
}

回答1:


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.




回答2:


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*.




回答3:


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.



来源:https://stackoverflow.com/questions/59720473/method-to-pass-double-to-void-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!