C++/CLI MSIL 程序集中的指针数组

2024-01-30

我正在尝试包装一些遗留的 C 代码,以便与在 .NET Core 上运行的 C# 一起使用。我在用着这里给出的方法 https://stackoverflow.com/a/9004833创建编译为纯 MSIL 的 C++ 包装器。它对于简单的函数运行良好,但我发现如果我的代码曾经使用指向指针的指针或指针数组,它将因内存冲突而崩溃。它经常使 Visual Studio 崩溃,我必须重新启动一切,这很乏味。

例如,以下代码将导致崩溃:

public ref class example
    {
    public:

        static void test() {
            Console::WriteLine("\nTesting pointers.");

            double a[5] = {5,6,7,8,9}; //Array.
            double *b = a; //Pointer to first element in array.

            Console::WriteLine("\nTesting bare pointers.");
            Console::WriteLine(a[0]); //Prints 5.
            Console::WriteLine(b[0]); //Prints 5.

            Console::WriteLine("\nTesting pointer-to-pointer.");
            double **c = &b;
            Console::WriteLine(c == &b); //Prints true.
            Console::WriteLine(b[0]); //Works, prints 5.
            Console::WriteLine(**c); //Crashes with memory access violation.

            Console::WriteLine("\nTesting array of pointers.");
            double* d[1];
            d[0] = b;
            Console::WriteLine(d[0] == b); //Prints false???
            Console::WriteLine(b[0]); //Works, prints 5.
            Console::WriteLine(d[0][0]); //Crashes with memory access violation.

            Console::WriteLine("\nTesting CLI array of pointers.");
            cli::array<double*> ^e = gcnew cli::array<double*> (5);
            e[0] = b;
            Console::WriteLine(e[0] == b); //Prints false???
            Console::WriteLine(b[0]); //Works, prints 5.
            Console::WriteLine(e[0][0]); //Crashes with memory access violation.
        }
}

请注意,简单地使用指针不会导致任何问题。只有当存在额外的间接级别时才会出现这种情况。

如果我将代码放入 CLR C++ 控制台应用程序中,它会完全按预期工作并且不会崩溃。仅当将代码编译为 MSIL 程序集时才会发生崩溃clr:pure并从 .NET Core 应用程序运行。

可能发生什么事?

更新1:以下是 Visual Studio 文件:https://app.box.com/s/xejfm4s46r9hs0inted2kzhkh9qzmjpb https://app.box.com/s/xejfm4s46r9hs0inted2kzhkh9qzmjpb这是两个项目。 MSIL 程序集称为libraryCoreApp是一个将调用该库的 C# 控制台应用程序。警告,运行 Visual Studio 时可能会崩溃。

更新2:我也注意到了这一点:

        double a[5] = { 5,6,7,8,9 };
        double* d[1];
        d[0] = a;
        Console::WriteLine(d[0] == a); //Prints true.
        Console::WriteLine(IntPtr(a)); //Prints a number.
        Console::WriteLine(IntPtr(d[0])); //Prints a completely different number.

这看起来像是生成的 IL 中的问题test方法。在崩溃发生时我们正在阅读**c, and c是本地号码 5。

IL_00a5  11 05             ldloc.s      0x5
IL_00a7  4a                ldind.i4    
IL_00a8  4f                ldind.r8    
IL_00a9  28 11 00 00 0a    call         0xA000011

所以在这里我们看到IL说要加载的值c,然后加载一个 4 字节有符号整数,然后将该整数视为指针并加载 8 字节实数类型(双精度型)。

在 64 位平台上,指针应该是大小中性的或 64 位的。所以ldind.i4这是有问题的,因为底层地址是 8 字节。由于 IL 指定仅读取 4 个字节,因此 jit 必须扩展结果以获得 8 个字节的值。这里选择签署extend。

library.h @ 27:
00007ffd`b0cf2119 488b45a8        mov     rax,qword ptr [rbp-58h]
00007ffd`b0cf211d 8b00            mov     eax,dword ptr [rax]
00007ffd`b0cf211f 4863c0          movsxd  rax,eax   // **** sign extend ****
>>> 00007ffd`b0cf2122 c4e17b1000      vmovsd  xmm0,qword ptr [rax]
00007ffd`b0cf2127 e854f6ffff      call    System.Console.WriteLine(Double) (00007ffd`b0cf1780)

在完整框架上运行时,您显然很幸运,因为数组地址很小并且适合 31 位或更少,因此读取 4 个字节,然后符号扩展到 8 个字节仍然给出正确的地址。但在 Core 上却没有,这就是应用程序崩溃的原因。

看来您使用 Win32 目标生成了库。如果您使用 x64 目标重建它,IL 将使用 64 位加载*c:

IL_00ab:  ldloc.s    V_5
IL_00ad:  ldind.i8
IL_00ae:  ldind.r8
IL_00af:  call       void [mscorlib]System.Console::WriteLine(float64)

并且该应用程序运行得很好。

看来这是 C++/CLI 中的一个功能——即使在纯模式下,它生成的二进制文件也隐式依赖于体系结构。仅有的/clr:safe可以生成与体系结构无关的程序集,并且您不能将其与此代码一起使用,因为它包含无法验证的结构(如指针)。

另请注意,.Net Core 2.x 并不支持 C++/CLI 的所有功能。这个特定的示例避免了不支持的位,但更复杂的位可能不会。

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

C++/CLI MSIL 程序集中的指针数组 的相关文章

  • 任务并行库周围是否有一个接口包装器,以便我可以将其交换用于单元测试?

    I asked 这个问题 https stackoverflow com questions 3362734 unit testing concurrent software what do you do不久以前 我现在知道这是一个坏主意
  • C#动态支持吗?

    看完之后这个帖子 https stackoverflow com questions 2674906 when should one use dynamic keyword in c sharp 4 0k和链接 我还有 2 个问题 问题 1
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 检查算术运算中的溢出情况[重复]

    这个问题在这里已经有答案了 可能的重复 检测 C C 中整数溢出的最佳方法 https stackoverflow com questions 199333 best way to detect integer overflow in c
  • C 语言中 =+(等于加)是什么意思?

    我碰到 与标准相反 今天在一些 C 代码中 我不太确定这里发生了什么 我在文档中也找不到它 In ancientC 版本 相当于 它的残余物与最早的恐龙骨头一起被发现 例如 B 引入了广义赋值运算符 使用x y to add y to x
  • 在非活动联合成员上使用“std::addressof”是否定义明确[重复]

    这个问题在这里已经有答案了 下面的代码是尝试实现constexpr的版本offsetof在 C 11 中 它可以在 gcc 7 2 0 和 clang 5 0 0 中编译 这取决于申请std addressof工会非活跃成员的成员 这是明确
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 将构建日期放入“关于”框中

    我有一个带有 关于 框的 C WinForms 应用程序 我使用以下方法将版本号放入 关于 框中 FileVersionInfo GetVersionInfo Assembly GetExecutingAssembly Location F
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 如何一步步遍历目录树?

    我发现了很多关于遍历目录树的示例 但我需要一些不同的东西 我需要一个带有某种方法的类 每次调用都会从目录返回一个文件 并逐渐遍历目录树 请问我该怎么做 我正在使用函数 FindFirstFile FindNextFile 和 FindClo
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 剪贴板在 .NET 3.5 和 4 中的行为有所不同,但为什么呢?

    我们最近将一个非常大的项目从 NET Framework 3 5 升级到 4 最初一切似乎都工作正常 但现在复制粘贴操作开始出现错误 我已经成功制作了一个小型的可复制应用程序 它显示了 NET 3 5 和 4 中的不同行为 我还找到了一种解
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • WinRT 定时注销

    我正在开发一个 WinRT 应用程序 要求之一是应用程序应具有 定时注销 功能 这意味着在任何屏幕上 如果应用程序空闲了 10 分钟 应用程序应该注销并导航回主屏幕 显然 执行此操作的强力方法是在每个页面的每个网格上连接指针按下事件 并在触
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项
  • 实例化 Microsoft.Office.Interop.Excel.Application 对象时出现错误:800700c1

    实例化 Microsoft Office Interop Excel Application 以从 winforms 应用程序生成 Excel 时 出现以下错误 这之前是有效的 但突然间它停止工作了 尽管代码和 Excel 版本没有变化 我

随机推荐

  • 根据 groupby 之后其他列中的值之间的数据帧范围对单独的列求和

    我有一个数据框如下 id Supply days days 180 1 30 0 180 1 100 183 363 1 80 250 430 2 5 0 180 2 5 10 190 3 5 0 180 3 30 100 280 3 30
  • JQGrid是免费的吗?

    从以下位置下载 JQGrid js 文件http www trirand com blog http www trirand com blog 免费吗 这是什么http www trirand net demoaspnetmvc aspx
  • 安卓屏幕分辨率

    Android 中已经定义了一些屏幕分辨率 他们是 QVGA 240 320 低密度 小屏幕 WQVGA 240 400 低密度 普通屏幕 FWQVGA 240 432 低密度 普通屏幕 HVGA 320 480 中等密度 普通屏幕 WVG
  • NameError:Python 中未定义名称“reduce”

    我正在使用Python 3 2 尝试过这个 xor lambda x y x y 2 l reduce xor 1 2 3 4 并得到以下错误 l reduce xor 1 2 3 4 NameError name reduce is no
  • 什么可能导致 MSIExec 错误 1619“无法打开此安装包”

    我正在尝试从一组示例程序中自动执行一组 MSI 文件 由 WiX 生成 的往返安装和卸载 由于某种原因 双击后会生成一个非常适合安装的 MSI 文件 无法打开该安装包 验证该包是否存在并且您可以访问它 或者联系应用程序供应商以验证这是否是有
  • 在后台获取核心数据

    我有一个带有表视图的导航视图 当单击一行时 行索引路径将传递到下一个视图 在详细信息视图 viewDidLoad 中 我正在从 Core Data 获取数据 我使用从应用程序委托中获取 appDelegate loadItem i 正如你所
  • publicId 和 systemId 之间需要空格

    我试图通过在 jsp 中编写一些代理代码来从我的计算机本地对其他域进行 ajax 调用 这是我调用 proxy jsp 页面的 jQuery AJAX 代码 var metadata https rest search host com m
  • 是否可以从 clickhouse 表中删除旧记录?

    据我所知 clickhouse只允许插入新数据 但是是否可以删除早于某个时间段的块以避免硬盘溢出 轻量级删除 自 v22 8 起可用 MergeTree 表的标准 DELETE 语法已在 37893 https github com Cli
  • 不存在的列不应破坏 select 中的 sql 查询

    就我而言 有不同的数据库版本 SQL Server 例如我的桌子orders有专栏htmltext在版本 A 中 但在版本 B 中列htmltext不见了 Select order id order date htmltext from o
  • 在迭代器中访问 C# 基类会导致 ReSharper 警告

    我有两节课GenericList and SpecificList where SpecificList继承自GenericList GenericList实施IEnumerable
  • WCF双工服务通道关闭

    我有一个基于 WCF Duplex 服务的应用程序 当用户 重新启动 应用程序所做的工作时 我遇到问题 在后台 客户端关闭与 WCF 服务的连接并创建另一个连接 服务合同的定义如下 ServiceContract Namespace net
  • Spark/Scala 中将 RDD 转换为 Dataframe

    RDD 已按以下格式创建Array Array String 并具有以下值 val rdd Array Array String Array Array 4580056797 0 2015 07 29 10 38 42 0 1 1 Arra
  • Python 3.4:cStringIO 与 StringIO

    QUESTION 我返回一个 ImportError 没有名为 cStringIO 的模块 不幸的是 cStringIO 不再存在 我需要使用 StringIO 作为替代品 我怎样才能做到这一点 import edgar import ft
  • 在 Jinja 模板中使用 Ansible 控制主机的 IP 地址

    我想将 IP 地址插入到 Ansible playbook 使用的 J2 模板中 该IP地址是not正在配置的主机的地址 以及完成配置的主机的 IP 到目前为止我发现的所有内容都涵盖了使用与所配置的主机相关的变量 事实 换句话说 我要插入的
  • .NET 4.0 与 3.5 运行时性能

    现在 VS2010 已处于 RC 状态 距离 2 0 以来第一个新 核心 运行时版本的发布似乎只剩下几周的时间了 虽然我没有立即升级的需求 但我想知道是否有人在两者之间进行了一些性能测试 基准测试 如果有任何明显的性能提升 那么重新编译现有
  • “FirebaseAnalytics.Param.SIGN_UP_METHOD”无法在控制台中保存“值”以及“事件名称”

    我正在使用此代码来分析用户正在使用的sign up方法 Bundle bundle new Bundle bundle putString FirebaseAnalytics Param SIGN UP METHOD sign up met
  • Visio 形状 - 获取 X、Y 位置

    我已成功使用以下代码以编程方式将形状插入到 Visio 中 ActiveWindow Page Drop VisioApp Documents ORGCH M VSS Masters ItemU Executive 5 433071 7 5
  • App Engine Java 8 标准环境中的 Servlet 异步处理支持

    我正在尝试使用 GAE J8 标准环境 无可扩展环境 的 servlet 3 1 中的异步处理支持 基本上我有一个 servlet 注释为 WebServlet name MyServletName urlPatterns dosometh
  • 如何在javafx代码中添加Anchorpane约束?

    我知道您可以在 fxml 中添加 Anchor Pane 包含 例如 AnchorPane bottomAnchor 0 0 但是您可以在 java 代码中设置 AnchorPane 约束吗 AnchorPane 上有一组静态方法 您可以使
  • C++/CLI MSIL 程序集中的指针数组

    我正在尝试包装一些遗留的 C 代码 以便与在 NET Core 上运行的 C 一起使用 我在用着这里给出的方法 https stackoverflow com a 9004833创建编译为纯 MSIL 的 C 包装器 它对于简单的函数运行良