使用 LayoutKind.Explicit 进行布尔编组,这是否已损坏或按设计失败?

2023-12-10

首先,布尔类型据说有一个四字节值的默认编组类型。所以下面的代码有效:

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

显然,这些结构独立编组得很好。这些值按预期转换。然而,当我们通过像这样声明 LayoutKind.Explicit 将这些结构组合成一个“联合”时:

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

我们突然发现自己无法正确地整理这些类型。以下是上述结构的测试代码以及​​它是如何失败的:

        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

看到这个表达为 true 是非常幽默的: (a.bValue1 != false && a.bValue1 == true && !true.Equals(a.bValue1))

当然,这里更大的问题是 a.iValue2 != 4,而不是 4 已更改为 1(大概是通过重叠的布尔值)。

那么问题来了:这是一个错误,还是只是按照设计失败了?

背景:本文来自 使用 PInvoke 时,包含 bool 与 uint 的结构有什么区别?

更新:当您使用大整数值(> 255)时,这甚至更奇怪,因为只有用于布尔值的字节被修改为 1,从而将 b.bValue2 的 0x0f00 更改为 0x0f01。对于上面的 a.bValue1,它根本没有被转换,并且 0x0f00 为 a.bValue1 提供了一个错误值。

更新#2:

对于上述问题,最明显、最合理的解决方案是使用 uint 进行编组并公开布尔属性。真正通过“解决方法”解决问题是没有问题的。我主要想知道这是一个错误还是您期望的行为?

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

它正在按设计工作。

这是正在发生的事情:

获取新的 int[] { 2, 4 } 并将其编组为 A、B、Broken 和 Broken2。 最后一个与 Broken 相同,但字段顺序相反(先是 b,然后是 a)。

如果我们将整数编组到这些结构中,我们会在内存中得到以下值:

  • A: 1, 4
  • B: 2, 1
  • 破损: 2, 1
  • 破碎2: 1, 4

所以发生的事情如下:

  • 当编组器遇到布尔值时,它的值为:bool = (original != 0);
  • 当有两个字段映射到同一内存时,最后一个字段的规则获胜

因此,对于 A,第一个 int 被转换为 1,对于 B,第二个 int 被转换为 1, 对于 Broken,由于 B 是最后一个字段,因此适用其规则,因此第二个 int 被转换为 1。对于 Broken2 也是如此。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 LayoutKind.Explicit 进行布尔编组,这是否已损坏或按设计失败? 的相关文章

  • 如何获取正在访问 ASP.NET 应用程序的当前用户?

    为了获取系统中当前登录的用户 我使用以下代码 string opl System Security Principal WindowsIdentity GetCurrent Name ToString 我正在开发一个 ASP NET 应用程
  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable

随机推荐

  • TextField - 在用户开始输入文本之前显示提示

    我正在开发一个黑莓应用程序 我想在用户开始输入之前在 TextField 中显示提示文本 当用户开始输入时 它应该消失 当 TextField 中有 0 个字符时 它应该显示 有人实现了这个吗 然后请分享 protected void pa
  • 如何使用 Bicep 部署带有 .Net 堆栈的 Windows Azure 应用服务?

    我创建了一个 Bicep 来部署带有 linux windows 选择和 net 6 堆栈的服务计划和应用服务 两次部署均成功 Linux 应用程序完全正常 门户网站上存在 net 6 堆栈 然而 Windows 堆栈门户屏幕上为空 我正在
  • 如何在VM之外访问安装在Azure VM(VM角色)上的sql服务器?

    我正在处理 Windows Azure VM 角色 我在 Azure VM 上安装了 sql 服务器 现在我想从外部连接到该 sql 服务器 这可能吗 请参考此链接配置您的VM角色 您需要的一部分是打开一个防火墙端口 允许与您的虚拟机角色进
  • 如何以编程方式从draw.io PNG中提取XML数据

    长话短说 我希望能够在浏览器中使用 PHP 或 JavaScript 从 Draw io 保存的 PNG 中提取 XML 数据 我使用带有图层的draw io 图像来记录网络设备之间的物理连接 文档站点是一个内部站点 运行dokuwiki例
  • NSURLSession 取消任务

    我使用以下配置创建新的 NSURLSession if self session NSURLSessionConfiguration config NSURLSessionConfiguration backgroundSessionCon
  • 如何确保 Athena 结果 S3 对象具有存储桶所有者完全控制

    我们 账户 A 希望以编程方式在不同的 aws 账户 账户 B 中触发 athena 查询 startQueryExecution 我们使用假定的角色来实现它 athena 查询完成后 我们期望结果应写入我们的 aws 账户 s3 存储桶
  • 当链接不包含 http 时 android.content.ActivityNotFoundException

    我的应用程序允许用户使用有限的 HTML 向其他用户输入消息 我允许的事情之一是使用超链接 Example a href www google com Google a 我正在填充TextView通过以下方法 txtview setMove
  • Mac OSX 上的 XAMPP:为什么作为“守护进程”运行? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我有点困惑 我在 Mac OSX Macbook 上的 XAMPP 中运行 Apache 服务器 我写了一个文件上传脚本并且运行良好 但上传的文件的所有者为 daemon 如何将我或
  • 将可变大小表单转换为 javascript 和 PHP (AJAX)

    背景 我有一个包含一堆按钮的网页 想想 POS 系统 我希望用户能够编辑按钮的名称 用于将它们按特定顺序排列 和按钮的文本 其中包含项目和成本两部分 目前 我通过将数据从 PHP 页面 完成编辑的地方 传递到另一个 PHP 页面 我将其写回
  • C 和它的抽象机之间的精确关系是什么?

    我正在读 C in a nutshell 里面有很多类似的句子 语句指定要执行的一个或多个操作 例如 为变量赋值 将控制权传递给函数 或者 跳到另一个声明 我的问题是 执行 这些动作的东西是什么 我到处读到过 C 被定义为在抽象机器上运行
  • ASP、MySQL 和 UTF-8

    首先 我几乎阅读了所有与此相关的主题 我已经尝试了所有建议 但无法解决这个问题 事情是这样的 我在一个项目中使用经典 ASP 和 MySQL 一切都很好 如果我写 一个例子 Response Write 它就像一个魅力 但是 如果该字符串来
  • MySQL SELECT 计数器、分组依据

    我不确定我所要求的是否可能 但它可能是哈哈 基本上 我有两张桌子 曲目和专辑 我想显示所有曲目的列表并从专辑部分获取名称 这些表看起来像这样 tbl tracks id int auto increment primary key albu
  • 如何获取黑莓当前位置的纬度和经度?

    我正在开发一个具有 GPS 功能的应用程序 如何获取当前位置的纬度和经度 我自己找到了解决方案 以下代码对我来说效果很好 package mypackage import javax microedition location Locati
  • Angularjs 格式日期

    Angular 中是否有任何指令 我想在用户在日期输入中写入 2 3 67 时启用用户 日期需要格式化为 02 03 1967 我自己尝试了一些东西 但它们不起作用 当显示用户输入时 只需添加 Angularjs 格式即可 yourdate
  • AngularJS指令输入宽度通过keyup调整大小

    我创建了一个指令 以便在键入时自动调整宽度的输入 如 Google 联系人 但似乎不行 因为每个字符的宽度不同 您能帮我提供一个更优化的方法吗 谢了 http plnkr co edit DSn0JDDShOXvuXXF9PP2 p pre
  • 除非提供“--jsx”标志,否则无法使用 JSX

    我四处寻找这个问题的解决方案 他们都建议添加 jsx react 到您的 tsconfig json 文件 我已经做到了 另一种是添加 include 我也做过 但是 当我尝试编辑时仍然收到错误 tsx文件 下面是我的 tsconfig 文
  • Chrome 扩展:(DOM)调试器 API 不再工作

    自版本 37 0 2062 103 以来 我们的 Chrome 扩展程序不再正常工作 它曾经在 chrome 版本 36 0 1985 143 上正常工作 具体来说 当我们使用 DOMDebugger 时 调试器 API 已停止为我们工作
  • Apple Wallet:Push Token 对于每个设备来说都是唯一的吗?

    我已经实现了一个可以为苹果钱包创建通行证的实现 一旦设备向服务器注册 就会推送该设备唯一的令牌 还是将来最终会改变 若有 原因为何 是的 为了保护隐私 推送令牌会定期轮换 这可能会随机发生 或者随着硬件的变化 用户转移到新手机 或者经常随着
  • 开发人员可以使用哪些选项来使用专用标签打印机进行打印?

    我们的业务使用定制的内部软件来创建要在大型高速标签打印机上打印的运输标签 开发人员可以使用哪些选项 库 服务 成熟软件等 来协助创建自定义格式标签并将其发送到专用标签打印机的过程 更多背景信息 Instead of using softwa
  • 使用 LayoutKind.Explicit 进行布尔编组,这是否已损坏或按设计失败?

    首先 布尔类型据说有一个四字节值的默认编组类型 所以下面的代码有效 struct A public bool bValue1 public int iValue2 struct B public int iValue1 public boo