"Jeremie Pelletier" <jerem...@gmail.com> wrote in message news:h9q1pn$1po...@digitalmars.com... > Nick Sabalausky wrote: >> >> Unions are nothing more than an alternate syntax for a reinterpret cast. >> And it's an arguably worse syntax because unlike casts, uses of it are >> indistinguishable from normal safe code, there's nothing to grep for. As >> such, unions should never be considered any more safe than cast(x)y. > > Yet it's the only way I know of to do bitwise logic on floating points in > D to extract the exponent, sign and mantissa for example. >
--------------------------------- // Something along these lines, it compiles, but I didn't test it. float f; // f = ...; // Of course, normally I'd wrap these in funcs or something. bool f_sign = (cast(uint)f & 0x8000_0000) != 0; uint tmp = cast(uint)f << 1; byte f_exponent = (*(cast(byte[4]*)&tmp))[3]; uint f_mantissa = cast(uint)f & 0x007F_FFFF; // ... use f_sign, f_exponent, and f_mantissa here ... // Set just sign f = (cast(int)f_sign << 31) | (cast(uint)f & 0x7FFF_FFFF); // Set just exponent uint tmp_exp = f_exponent; f = (tmp_exp <<= 23) | (cast(uint)f & 0x807F_FFFF); // Set just mantissa f = f_mantissa | (cast(uint)f & 0xFF80_0000); --------------------------------- I'm not sure how you'd do that with D's unions though, since the components don't align on byte boundaries and D's structs don't allow bitfields. > And yes they are much, much more than a simple reinterpret cast, a simple > set of casts will not set the size of the union to its largest member. --------------------------------- union myUnion { int i; byte b; long l; short s; } myUnion u; int i = u.i; byte b = u.b; long l = u.l; short s = u.s; // ---> long u_l; int i = cast(int)u_l; byte b = cast(byte)u_l; long l = u_l; short s = cast(short)u_l; --------------------------------- A union is semantically the same as a single variable of it's largest member with reinterpret casts used to access the smaller members. > Unions make for elegant types which can have many valid representations: > > union Vec3F { > struct { float x, y, z; } > float[3] v; > } > Yes, it can make the syntax cleaner in certain cases, and just like casts there are certain cases where it is perfectly safe and useful. But the semantics are still the same: --------------------------------- struct Struct3F { float x, y, z; } Struct3F s3f; (*(cast(float[3]*)&s3f))[0] = 1; (*(cast(float[3]*)&s3f))[1] = 2; (*(cast(float[3]*)&s3f))[2] = 3; Stdout.formatln("s3f.x: {}", s3f.x); // 1 Stdout.formatln("s3f.y: {}", s3f.y); // 2 Stdout.formatln("s3f.z: {}", s3f.z); // 3 float[3] a3f; (cast(Struct3F)a3f).x = 1; (cast(Struct3F)a3f).y = 2; (cast(Struct3F)a3f).z = 3; Stdout.formatln("a3f[0]: {}", a3f[0]); // 1 Stdout.formatln("a3f[1]: {}", a3f[1]); // 2 Stdout.formatln("a3f[2]: {}", a3f[2]); // 3 --------------------------------- Of course, in this particular case, you could still avoid using casts or unions entirely if you wanted to: --------------------------------- typedef float[3] Vec3F; enum Coord { X, Y, Z } Vec3F v; //... assert( v[1] == v[Coord.Y] ); --------------------------------- > I just can't picture D without unions :) I can't picture D without unions *or* without casts. They certainly both have their uses, particularly in a systems language. I'm not trying to argue against that. I'm just saying that a union is effectively just another way of reinterpret casting and as such should never be considered any more safe than reinterpret cast.