问题
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