Reputation: 3345
I just discovered some dodgy problems when i was interleaving some floats. I've simplified the issue down and tried some tests
#include <iostream>
#include <vector>
std::vector<float> v; // global instance
union{ // shared memory space
float f; // to store data in interleaved float array
unsigned int argb; // int color value
}color; // global instance
int main(){
std::cout<<std::hex; // print hexadecimal
color.argb=0xff810000; // NEED A==ff AND R>80 (idk why)
std::cout<<color.argb<<std::endl; // NEED TO PRINT (i really dk why)
v.insert(v.end(),{color.f,0.0f,0.0f}); // color, x, y... (need the x, y too. heh..)
color.f=v[0]; // read float back (so we can see argb data)
std::cout<<color.argb<<std::endl; // ffc10000 (WRONG!)
}
the program prints
ff810000
ffc10000
If someone can show me i'm just being dumb somewhere that'd be great.
update: turned off optimizations
#include <iostream>
union FLOATINT{float f; unsigned int i;};
int main(){
std::cout<<std::hex; // print in hex
FLOATINT a;
a.i = 0xff810000; // store int
std::cout<<a.i<<std::endl; // ff810000
FLOATINT b;
b.f = a.f; // store float
std::cout<<b.i<<std::endl; // ffc10000
}
or
#include <iostream>
int main(){
std::cout<<std::hex; // print in hex
unsigned int i = 0xff810000; // store int
std::cout<<i<<std::endl; // ff810000
float f = *(float*)&i; // store float from int memory
unsigned int i2 = *(unsigned int*)&f; // store int from float memory
std::cout<<i2<<std::endl; // ffc10000
}
solution:
#include <iostream>
int main(){
std::cout<<std::hex;
unsigned int i=0xff810000;
std::cout<<i<<std::endl; // ff810000
float f; memcpy(&f, &i, 4);
unsigned int i2; memcpy(&i2, &f, 4);
std::cout<<i2<<std::endl; // ff810000
}
Upvotes: 0
Views: 226
Reputation: 117688
Writing to the int and then reading from the float in the union causes UB. If you want to create a vector of mixed value types, make a struct to hold them. Also, don't use unsigned int
when you need exactly 32 bits. Use uint32_t
.
#include <iostream>
#include <vector>
struct gldata {
uint32_t argb;
float x;
float y;
};
std::vector<gldata> v;
int main() {
std::cout << std::hex; // print hexadecimal
v.emplace_back(gldata{0xff810000, 0.0f, 0.0f});
std::cout << v[0].argb << "\n"; // 0xff810000
}
Upvotes: 2
Reputation: 32727
The behavior you're seeing is well defined IEEE floating point math.
The value you're storing in argb
, when interpreted as a float will be a SNaN (Signaling NaN). When this SNaN value is loaded into a floating point register, it will be converted to a QNaN (Quiet NaN) by setting the most significant fraction bit to a 1 (and will raise an exception if floating point exceptions are unmasked).
This load will change your value to from ff810000
to ffc10000
.
Upvotes: 3