first let me say I know the following code will be considered “bad” practices.. But I’m limited by the environment a “little” bit:
In an dynamic library I wish to use “pointers” (to point to classes) – however the program that will use this dll, can only pass & receive doubles. So I need to “fit” the pointer in a double. The following code tries to achieve this, which I hope to work in a 64-bit environment:
EXPORT double InitializeClass() {
SampleClass* pNewObj = new SampleClass;
double ret;
unsigned long long tlong(reinterpret_cast<unsigned long long>(pNewObj));
memcpy(&ret, &tlong, sizeof(tlong));
return ret;
}
EXPORT double DeleteClass(double i) {
unsigned long long tlong;
memcpy(&tlong, &i, sizeof(i));
SampleClass* ind = reinterpret_cast<SampleClass* >(tlong);
delete ind;
return 0;
}
Now once again I realize I might’ve been better of using vectors & storing the pointers inside the vector. However I really wish to do this using pointers (as alternative). So can anyone tell me possible failures/better versions?
The obvious failure is if double & unsigned long long aren’t the same length in size (or pointers being longer than 64 bits). Is there a method to check this at compile time? – And give a compile error in case the sizes aren’t the same?
In theory, at least, a 64 bit pointer, type punned to a 64 bit IEEE
double, could result in a trapping NaN, which would in turn trap. In
practice, this might not be a problem; my attempts to get trapping NaN
to actually do something other than be ignored have not been very
successful.
Another possible problem is that the values might not be normalized
(and in fact, probably won’t be). What the hardware does with
non-normalized values depends: it could either just pass them on
transparently, silently normalize them (changing the value of the
“pointer”), or trigger some sort of runtime error.
There’s also the issue of aliasing. Accessing a pointer through an
lvalue which has a type of
doubleis undefined behavior, and manycompilers will take advantage of this when optimizing, assuming that
changes through a
double*or adouble&reference cannot affect anypointers (and moving the load of the pointer before the write of the
double, or not reloading the pointer after a modification of the
double).
In practice if you’re working in an Intel environment, I think all
“64-bit” pointers will in fact have the upper 16 bits 0. This is where
the exponent lives in an IEEE double, and an exponent of 0 is a gradual
underflow, which won’t trap (at least with the default modes), and won’t
be changes. So your code might actually seem to work, as long as the
compiler doesn’t optimize too much.