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

C# 显式结构布局上的未分配字段,c#,struct,structlayout,C#,Struct,Structlayout,我想生成一个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 >>

我想生成一个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;
u、 x=x;

u、 i=(1>1)-(1
FieldOffset
主要是一种互操作功能;它告诉运行时在本机上下文中使用时应该如何封送结构。在某些情况下(blittable结构),它还影响受管内存布局。应注意,任何显式结构布局都意味着代码不再可移植。这可能是代码的问题,也可能不是代码的问题

重要的一点是,除了一些非常简单的启发式方法之外,编译器甚至不会尝试验证不安全的代码;它仍然会看到两个字段,并且您从未分配其中一个字段,因此您违反了
struct
约定。这与使用指针算法访问字段没有太大区别。它仍然更重要很可能是您犯了一个错误,忘了分配一个字段,而这正是您想要的。如果您真的想分配,您可以在读取字段之前进行分配(或者使用构造函数;C#不是C,并且
U=new U();
通常很好)

但在您的情况下,没有什么理由使用联合字段。如果您想执行这样的非托管操作,请使用不安全的代码。这就是它的目的。不要滥用互操作功能。当然,无论您选择哪种方式,都不要期望它是可移植的

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;
}
不安全的void Main()
{
sqrt(42.Dump();//6.625
sqrt(9.Dump();//3.125
}
不安全浮点sqrt(浮点x)
{
int*pX=(int*)((void*)和x);

*pX=(1>1)-(1不,你不能忽略。只需添加它。但是…你为什么要在C#?!?!中模拟并集?你可以使用
BitConverter
。使用浮点数…对于基准,我不需要赋值,只需计算
sqrt()
,将不会测量
u.i
的额外分配。如果您真的想这样做,请选择慢一点的方式:@AdrianoRepetti primary C function作为联合体,我只想复制为C(ish)尽可能。BitConverter似乎比基本的“模拟”并集慢,但如果它是错误的,我会使用它。顺便说一句,我同意额外的分配。检查链接帖子,在接受的答案中有
不安全的
内存访问,应该和C
并集
一样快,我认为这样说不正确“托管端将把
i
放在与
x
相同的内存上。”显式结构布局用于通过位定位进行中断,在您的情况下,这将不起作用。您的
(int*)((void*)&x);
被转换为
(int*)&x
在IL代码上,但你说得对,它似乎比使用struct快,我将两者都放在板凳上。谢谢@Luaan!@FlorianJ我写道,你不能保证会发生这种情况,也就是说,与你读到的相反:)
StructLayout
(和
FieldOffset
)是为了互操作-他们对托管内存布局所做的任何更改都是一个实现细节,而不是您可以依赖的。同样,获取字段指针是安全的,但不要向该指针添加偏移量,并期望在那里找到不同的字段-这根本不是合同的一部分。FieldOffset是互操作功能,而不是其他功能ng应该以任何方式影响托管代码。这实际上是不正确的。
LayoutKind.Explicit
…影响托管和非托管布局,包括可blittable和不可blittable类型。@Luaan这是ECMA-335的直接引用:II.10.7控制实例布局;II.16定义和引用字段;II.22.16 FieldLayout。