显式结构布局上的未分配字段



我想产生一个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.X时分配了U.I,因此可以在编译时忽略未分配的现场错误而无需明确的u.i分配?

FieldOffset主要是Interop功能;它讲述了在本机上下文中使用时运行时应如何元帅。在某些情况下(可亮结构),它也会影响托管内存布局。应当指出,任何明确的结构布局都意味着代码不再是便携式的。对于您的代码而言,这可能不是问题。

重要的部分是编译器甚至没有试图验证一些非常简单的启发式方法的不安全代码。它仍然看到两个字段,并且您永远不会分配其中一个字段,因此您违反了struct合同。这与使用例如使用没有太大不同。指针算术可以访问该字段。您犯了一个错误并忘记分配字段的可能性仍然更大,而这显然是您想要的。如果您真的愿意,则可以进行分配(或使用构造函数; C#不是C,而U u = new U();通常很好) 阅读字段。

但是,就您而言,无论如何都没有理由使用联合领域。如果您想这样做不受管理的操作,请使用不安全的代码。就是这样。不要滥用Interop功能。当然,无论您选择哪种方式,都不要期望它是便携的。

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;
}

最新更新