Null references redux
Nick Sabalausky
a at a.a
Mon Sep 28 15:05:40 PDT 2009
"Jeremie Pelletier" <jeremiep at gmail.com> wrote in message
news:h9q1pn$1pok$1 at 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.
More information about the Digitalmars-d
mailing list