FieldOffset
is primarily an interop feature; it tells how the runtime should marshal the structure when used in a native context. In some cases (blittable structures), it also affects the managed memory layout. It should be noted that any explicit structure layout will mean the code is no longer portable. That may or may not be a problem for your code.
The important part is that the compiler does not even try to verify unsafe code beyond a few very simple heuristics; it still sees two fields, and you're never assigning one of the fields, so you're violating the struct
contract. This is not much different from using e.g. pointer arithmetic to access the field. It's still much more likely that you made a mistake and forgot to assign a field than that this is explicitly what you want. If you really want to, you can just do an assignment (or use a constructor; C# isn't C, and U u = new U();
is usually perfectly fine) before reading the field.
But in your case, there's little reason to use a union field anyway. If you want to do unmanaged operations like this, use unsafe code. That's what it's for. Don't abuse interop features. And of course, whichever way you choose, don't expect it to be portable.
float x = 42.0f;
(*(int*)((void*)&x)) // The value of `x` reinterpreted as an int
A full example of your sqrt approximation might look something like this:
unsafe void Main()
{
sqrt(42).Dump(); // 6.625
sqrt(9).Dump(); // 3.125
}
unsafe float sqrt(float x)
{
int* pX = (int*)((void*)&x);
*pX = (1 << 29) + (*pX >> 1) - (1 << 22);
return x;
}