显式结构布局上的未分配字段
unassigned field on explicit struct layout
我想生成一个 C# sqrt 基准,但一些 sqrt 函数需要一个联合来进行按位计算。
我的工会是这样定义的:
[StructLayout(LayoutKind.Explicit)]
struct U
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public float x;
}
下一个代码在 u.i
上产生未分配字段错误:
U u;
u.x = x;
u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
我知道 u.i 在 u.x 也被赋值时被赋值,所以是否可以在编译时忽略未赋值字段错误而无需显式 u.i
赋值?
FieldOffset
主要是一个互操作特性;它告诉运行时在本机上下文中使用时应如何编组结构。在某些情况下(blittable 结构),它还会影响托管内存布局。应该注意的是,任何明确的结构布局都意味着代码不再可移植。这对您的代码来说可能是问题,也可能不是问题。
重要的是,编译器甚至不会尝试验证一些非常简单的试探法以外的不安全代码;它仍然看到两个字段,而您永远不会分配其中一个字段,因此您违反了 struct
合同。这与使用例如访问字段的指针算法。与您明确想要的相比,您犯错并忘记分配字段的可能性要大得多。如果你真的想要,你可以只做一个赋值(或使用构造函数;C# 不是 C,U u = new U();
通常完全没问题)before 读取字段。
但在您的情况下,无论如何都没有理由使用联合字段。如果你想像这样进行非托管操作,请使用不安全代码。这就是它的用途。不要滥用互操作特性。当然,无论您选择哪种方式,都不要指望它是便携的。
float x = 42.0f;
(*(int*)((void*)&x)) // The value of `x` reinterpreted as an int
您的 sqrt 近似值的完整示例可能如下所示:
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;
}
我想生成一个 C# sqrt 基准,但一些 sqrt 函数需要一个联合来进行按位计算。
我的工会是这样定义的:
[StructLayout(LayoutKind.Explicit)]
struct U
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public float x;
}
下一个代码在 u.i
上产生未分配字段错误:
U u;
u.x = x;
u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
我知道 u.i 在 u.x 也被赋值时被赋值,所以是否可以在编译时忽略未赋值字段错误而无需显式 u.i
赋值?
FieldOffset
主要是一个互操作特性;它告诉运行时在本机上下文中使用时应如何编组结构。在某些情况下(blittable 结构),它还会影响托管内存布局。应该注意的是,任何明确的结构布局都意味着代码不再可移植。这对您的代码来说可能是问题,也可能不是问题。
重要的是,编译器甚至不会尝试验证一些非常简单的试探法以外的不安全代码;它仍然看到两个字段,而您永远不会分配其中一个字段,因此您违反了 struct
合同。这与使用例如访问字段的指针算法。与您明确想要的相比,您犯错并忘记分配字段的可能性要大得多。如果你真的想要,你可以只做一个赋值(或使用构造函数;C# 不是 C,U u = new U();
通常完全没问题)before 读取字段。
但在您的情况下,无论如何都没有理由使用联合字段。如果你想像这样进行非托管操作,请使用不安全代码。这就是它的用途。不要滥用互操作特性。当然,无论您选择哪种方式,都不要指望它是便携的。
float x = 42.0f;
(*(int*)((void*)&x)) // The value of `x` reinterpreted as an int
您的 sqrt 近似值的完整示例可能如下所示:
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;
}