View Full Version : some cpp problem
feisty2
25th August 2015, 15:57
something came from me adding float support to MVTools
gotta store floats (SAD) as fake ints cuz the vector clip is like, uint8_t, and restore those fake stuff back to floats when something actually requires SAD data
I wrote 2 simple functions (FakeInt and Back2FLT) to do the work
#include <iostream>
using namespace std;
int FakeInt (float a)
{
int* ptr = (int*)&a;
return reinterpret_cast <int> (ptr);
}
float Back2FLT (int a)
{
int* ptr = reinterpret_cast <int*> (a);
return *((float*)ptr);
}
int main() {
float a = 1.5;
cout << Back2FLT(FakeInt(a)) << endl;
return 0;
}
and the test program above returned 2.28649e-038 instead of 1.5, what did I do wrong?
EDIT: typo
nevcairiel
25th August 2015, 16:19
You should use a union for this, more likely to not mess up.
union IntFloat {
int a;
float b;
};
Write int into IntFloat.a, read float from IntFloat.b, and vice-versa.
Note that if it converts it to uint8_t in between, it will destroy your float. Not sure what your uint8_t comment meant, however. :)
feisty2
25th August 2015, 17:00
like this?
int FakeInt(float a)
{
union whatever
{
float in;
int out;
}fake;
fake.in = a;
int* ptr = (int*)&fake.in;
fake.out = reinterpret_cast <int> (ptr);
return fake.out;
}
Note that if it converts it to uint8_t in between, it will destroy your float.
about that, guess MVtools already took care of it, it divides each int to 4 bytes and store them on a uint8_t frame
feisty2
25th August 2015, 17:13
#include <iostream>
using namespace std;
int FakeInt(float a)
{
union whatever
{
float in;
int out;
}fake;
fake.in = a;
int* ptr = (int*)&fake.in;
fake.out = reinterpret_cast <int> (ptr);
return fake.out;
}
float Back2FLT(int a)
{
union whatever
{
int in;
float out;
}fake;
fake.in = a;
int* ptr = reinterpret_cast <int*> (fake.in);
fake.out = *((float*)ptr);
return fake.out;
}
int main() {
float a = 1.5f;
cout << Back2FLT(FakeInt(a)) << endl;
return 0;
}
now I make the test program like this and still, no luck....
I got -1.07374e+008, not 1.5...
Groucho2004
25th August 2015, 17:18
#include <iostream>
using namespace std;
int FakeInt(float a)
{
union whatever
{
float in;
int out;
}fake;
fake.in = a;
int* ptr = (int*)&fake.in;
fake.out = reinterpret_cast <int> (ptr);
return fake.out;
}
float Back2FLT(int a)
{
union whatever
{
int in;
float out;
}fake;
fake.in = a;
int* ptr = reinterpret_cast <int*> (fake.in);
fake.out = *((float*)ptr);
return fake.out;
}
int main() {
float a = 1.5f;
cout << Back2FLT(FakeInt(a)) << endl;
return 0;
}
now I make the test program like this and still, no luck....
I got -1.07374e+008, not 1.5...
Don't you have a debugger with your VS?
wonkey_monkey
25th August 2015, 17:43
#include <stdio.h>
union flint {
int i;
float f;
};
int FakeInt(float a) {
flint temp;
temp.f = a;
return temp.i;
}
float Back2FLT(int a) {
flint temp;
temp.i = a;
return temp.f;
}
int main() {
float a = 1.5f;
printf("%f\n", a);
printf("%d\n", FakeInt(a));
printf("%f\n", Back2FLT(FakeInt(a)));
return 0;
}
You don't need ptr or the reinterpret_cast bit. You just assign to one member of the union, and read from the other.
I don't understand the whole reinterpret_cast syntax, but could your original problem be that you have reinterpret_cast <int> (ptr); twice, instead of one of them being reinterpret_cast <float> (ptr); ?
To simplify even further, couldn't you just cast your pointer to the data to a float*?
uint8_t dstp = dst->GetWritePtr();
((float*)dstp)[0]=1.5;
((float*)dstp)[1]=2.5;
There's probably a very good reason not to do it that way, but that's what I'd do.
LoRd_MuldeR
25th August 2015, 19:00
I don't understand the whole reinterpret_cast syntax...
In plain C, there is just the standard cast syntax with round brackets. But it is ambiguous! Sometimes it does a real conversion of the values, like when you cast from int to float, or the other way around. And sometimes it just "reinterprets" the bits without converting anything, like when you cast from one pointer type to another one. In C++, things have been made more explicit: With static_cast<T> you get a proper conversion. But it can only be used where such conversion is possible/defined. With reinterpret_cast<T> you can force the bits to be "reinterpreted" without any conversion. And then there is dynamic_cast<T>, which has no equivalent in plain C at all: It converts safely from an object-type to a more specific object-type - and, unlike static_cast<T>, it throws an exception, if the cast isn't possible. Of course you can still use the "old" C-style casting syntax in C++, but it's generally not considered "good style". It's more error-prone.
LoRd_MuldeR
25th August 2015, 19:20
and the test program above returned 2.28649e-038 instead of 1.5, what did I do wrong?
int* ptr = (int*)&a;
This line creates a pointer, which is pointing to the memory location where the float value "a" is stored. However, the type of this pointer is forced to int*, rather than float*. It's still pointing to some float data though!
Consequently, when the resulting "fake" int* pointer gets dereferenced at some later point, using the *-operator, then the data at that memory location will be interpreted as if it was int data - while there's actually float data at that location.
reinterpret_cast <int> (ptr);
That line changes the type of the pointer, i.e. memory address, "ptr" to the int type. I think this is problematic for (at least) two reasons:
On 64-Bit platforms, pointers are 64 bits in size. But the int type usually is only 32-Bit in size, even on 64-Bit platforms! Consequently, the memory address will be truncated. In other words, you'll get the 64-bit memory address modulo 2^32.
Furthermore, even on 32-Bit platforms there can be problems, because memory addresses (pointers) are unsigned, while int is signed! Memory addresses (pointers) higher than 0x7FFFFFFF will result in a negative int value...
(BTW: There is the special intptr_t type, which on every platform is an integer type guaranteed to be large enough to hold any pointer value)
wonkey_monkey
25th August 2015, 19:33
I didn't say I wanted to know ;)
But now I do, and will hopefully find it less scary when I encounter it in future, so :thanks:
(oh, and you wrote LameXP too, so thanks for that as well)
feisty2
26th August 2015, 04:57
wow, all these, really saved my ass.
thank you all! :)
jpsdr
26th August 2015, 09:00
@LoRd_MuldeR
I didn't know intptr_t, i assume it's unsigned. I was using size_t until now for doing this, is there any difference between them ?
According the name, of course, intptr_t seems more appropriate, like i always used ptrdiff_t for offset pointers.
EDIT :
Ok, i've just tested, it's not the same, intptr_t is always large enough, but no guarantee it will be of the same size, it can be bigger, but size_t is of the same size.
LoRd_MuldeR
26th August 2015, 19:06
I didn't know intptr_t, i assume it's unsigned. I was using size_t until now for doing this, is there any difference between them ?
They probably end up being the same on most platforms, but they are defined differently.
(u)intptr_t is an integral type with the following guarantee: If you cast any pointer to (u)intptr_t and then cast the resulting (u)intptr_t back to the pointer-type, you'll get a pointer equal to the original pointer. intptr_t is signed, so the "intermediate" intptr_t value may actually be negative. That's not a problem, as long as you just cast it back to the pointer-type. But I think you'll have to take special care with arithmetic operations. uintptr_t is the unsigned version.
size_t, on the other hand, is the return type of the sizeof() operator. So it is an unsigned type, large enough to hold the size (in bytes) of any possible object. This requirement probably comes down to the same as uintptr_t on most platforms. But the C standard is defined for many platforms. And, on some "exotic" or "archaic" platforms, there may actually be a difference. I think it could make a difference, for example, when segmented memory is involved. See this (http://stackoverflow.com/a/1464194) post for details...
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.