布尔编组与LayoutKind.Explicit,这是损坏或未按设计的? [英] Boolean Marshalling with LayoutKind.Explicit, Is this broken or failing as designed?

查看:169
本文介绍了布尔编组与LayoutKind.Explicit,这是损坏或未按设计的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所有的布尔类型的第一个是说有一个四字节值的默认元帅类型。所以下面code工作:

 一个结构
    {
        公共BOOL bValue1;
        公众诠释iValue2;
    }
    结构乙
    {
        公众诠释iValue1;
        公共BOOL bValue2;
    }
    公共静态无效的主要()
    {
        INT [] = rawvalues​​新INT [] {2,4};        A中的=(A)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues​​,GCHandleType.Pinned).AddrOfPinnedObject()的typeof(A));
        Assert.IsTrue(a.bValue1 == TRUE);
        Assert.IsTrue(a.iValue2 == 4);
        B B =(B)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues​​,GCHandleType.Pinned).AddrOfPinnedObject()的typeof(B));
        Assert.IsTrue(b.iValue1 == 2);
        Assert.IsTrue(b.bValue2 == TRUE);
    }

显然,这些结构元帅独立就好了。预期值折算。然而,当我们通过声明LayoutKind.Explicit像这样结合这些结构成一个联盟:

  [StructLayout(LayoutKind.Explicit)
    结构破碎
    {
        [FieldOffset(0)]
        公开发行A一;
        [FieldOffset(0)]
        大众B B;
    }

我们突然发现自己无法正确调度这些类型。下面是测试code为上述结构以及它是如何失败:

  INT [] = rawvalues​​新INT [] {2,4};
        破破的=(断)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues​​,GCHandleType.Pinned).AddrOfPinnedObject()的typeof(断));        Assert.IsTrue(broken.a.bValue1 =假的!); //通,没有虚假记载,
        Assert.IsTrue(broken.a.bValue1 ==真); //通,必须是真实的?
        Assert.IsTrue(true.Equals(broken.a.bValue1)); //失败,WOW,跆拳道?
        Assert.IsTrue(broken.a.iValue2 == 4); //失败,a.iValue1 == 1,发生了什么事4?
        Assert.IsTrue(broken.b.iValue1 == 2); //通
        Assert.IsTrue(broken.b.bValue2 ==真); //通

看到这个前preSS这是很幽默的是真的:(!a.bValue1 =假放;&安培; a.bValue1 ==真放;&安培; true.Equals(a.bValue1))

当然,这里的更大的问题是a.iValue2!= 4,而在4已经(由重叠的布尔presumably)改为1。

所以问题:这是一个错误,或者只是未能按设计

背景:这是来自 <一个href=\"http://stackoverflow.com/questions/1602899\">http://stackoverflow.com/questions/1602899

更新:当您使用大整数值(> 255),因为只有一个用于布尔字节被修改为1,从而改变0x0f00到0x0f01的b.bValue2这更奇怪。对于a.bValue1它上面根本不是翻译0x0f00提供a.bValue1一个假值。

更新#2:

以上问题(S)最明显和最合理的解决方案是使用一个UINT引导与公开布尔属性来代替。真正解决问题的一个处理方法是不是问题。我主要想知道这是一个错误或者这是你所期望的行为?

 一个结构
    {
        私人UINT _bValue1;
        公共BOOL bValue1 {{返回_bValue1!= 0; }}
        公众诠释iValue2;
    }
    结构乙
    {
        公众诠释iValue1;
        私人UINT _bValue2;
        公共BOOL bValue2 {{返回_bValue2!= 0; }}
    }


解决方案

这是事先设计好的。

下面是发生了什么:

以新的INT [] {2,4}并让名帅它分为A,B,破碎,和碎米。
最后是一样的破碎,但字段的顺序颠倒(第一个B,然后是)。

如果我们名帅整数到这些结构,我们在内存中得到以下值:


  • 答:1,4

  • A:2,1

  • 破碎:2,1

  • 碎米:1,4

所以发生的是以下内容:


  • 当编组遇到一个布尔值,它的价值是:(!原来= 0)BOOL =;

  • 当有两个字段映射到相同的存储器,最后一个字段赢的规则

等了,第一个int获取转换为1,B,第二int获取转换为1,
为打破,因为B是最后一个字段,它的规则,因此第二个INT被转换为1。同样,对于碎米。

First of all the Boolean type is said to have a default marshal type of a four-byte value. So the following code works:

    struct A 
    { 
        public bool bValue1; 
        public int iValue2; 
    }
    struct B 
    { 
        public int iValue1;
        public bool bValue2; 
    }
    public static void Main()
    {
        int[] rawvalues = new int[] { 2, 4 };

        A a = (A)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(A));
        Assert.IsTrue(a.bValue1 == true);
        Assert.IsTrue(a.iValue2 == 4);
        B b = (B)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(B));
        Assert.IsTrue(b.iValue1 == 2);
        Assert.IsTrue(b.bValue2 == true);
    }

Clearly these structures marshal independently just fine. The values are translated as expected. However, when we combine these structures into a "union" by declaring LayoutKind.Explicit like this:

    [StructLayout(LayoutKind.Explicit)]
    struct Broken
    {
        [FieldOffset(0)]
        public A a;
        [FieldOffset(0)]
        public B b;
    }

We suddenly find ourselves unable to correctly marshal these types. Here is the test code for the above structure and how it fails:

        int[] rawvalues = new int[] { 2, 4 };
        Broken broken = (Broken)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(Broken));

        Assert.IsTrue(broken.a.bValue1 != false);// pass, not false
        Assert.IsTrue(broken.a.bValue1 == true);// pass, must be true?
        Assert.IsTrue(true.Equals(broken.a.bValue1));// FAILS, WOW, WTF?
        Assert.IsTrue(broken.a.iValue2 == 4);// FAILS, a.iValue1 == 1, What happened to 4?
        Assert.IsTrue(broken.b.iValue1 == 2);// pass
        Assert.IsTrue(broken.b.bValue2 == true);// pass

It's very humorous to see this express as true: (a.bValue1 != false && a.bValue1 == true && !true.Equals(a.bValue1))

Of course the bigger problem here is that a.iValue2 != 4, rather the 4 has been changed to 1 (presumably by the overlapped bool).

So the question: Is this a bug, or just failed as designed?

Background: this came from http://stackoverflow.com/questions/1602899

Update: This is even stranger when you use large integer values (> 255) as only the byte that is used for the boolean is being modified to a 1, thus changing 0x0f00 to 0x0f01 for the b.bValue2. For a.bValue1 above it's not translated at all and 0x0f00 provides a false value for a.bValue1.

Update #2:

The most obvious and reasonable solution to the above issue(s) is to use a uint for the marshalling and expose boolean properties instead. Really solving the issue with a 'workaround' is not at question. I'm mostly wondering is this a bug or is this the behavior you would expect?

    struct A 
    { 
        private uint _bValue1;
        public bool bValue1 { get { return _bValue1 != 0; } } 
        public int iValue2; 
    }
    struct B 
    { 
        public int iValue1;
        private uint _bValue2;
        public bool bValue2 { get { return _bValue2 != 0; } } 
    }

解决方案

It is working as designed.

Here is what is happening:

Take the new int[] { 2, 4 } and lets marshal it into A, B, Broken, and Broken2. The last is the same as Broken, but with fields' order reversed (first b, then a).

If we marshal the ints into these structures we get the following values in memory:

  • A: 1, 4
  • B: 2, 1
  • Broken: 2, 1
  • Broken2: 1, 4

So what is happening is the following:

  • When the marshaller encounters a boolean, the value of it is: bool = (original != 0);
  • When there are two fields that map into the same memory, the rules of the last field win

So for A, the first int gets converted to 1, for B, the second int gets converted to 1, for Broken, since B is the last field, its rules apply, and hence the second int gets converted to 1. Similarly for Broken2.

这篇关于布尔编组与LayoutKind.Explicit,这是损坏或未按设计的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆