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