【问题标题】:Pinning adjacent fixed-sized buffers required?需要固定相邻的固定大小的缓冲区吗?
【发布时间】:2014-03-11 07:42:06
【问题描述】:

我一直致力于将旧的 C++ 应用程序移植到 C#,但我不确定我的解决方案是否真的可行。

最令人头疼的是该应用程序的文件格式本质上只是一些(相当大的)结构转储到文件中。有趣的部分是格式要求整数以大端顺序排列,无论系统如何。因此,我拼凑了一种实用方法来翻转字节顺序,并使用大量固定大小的缓冲区构建了复制 C++ 布局的结构。此时导入就像将文件复制到内存并使用Marshal.PtrToStructure 一样简单,这比手动读取要容易得多,但不会让我在构造时翻转字节顺序。

因此,格式在很大程度上取决于短变量,无论是单独的还是固定缓冲区中的。在将许多固定语句组合在一起以固定缓冲区以进行翻转的过程中,我有一个令人不安的想法。

除非我弄错了,否则只固定其中一个缓冲区会导致整个结构被固定(将结构的一部分从其余部分重新定位是没有意义的)。所以,我尝试过这样的事情:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct Example
{
    short value1;
    fixed short value2[10];
    short value3;
    fixed short value4[20];

    public void FlipEndianness()
    {
        fixed (short* ptr = &value1)
        {
            Utility.FlipShorts(ptr, 32);
        }
    }
}

这个想法是该实用程序方法适用于指针和计数,就像它是一个数组一样遍历指针 - 我最初编写它是为了翻转缓冲区,但我在这里看到了值。从理论上讲,它似乎工作正常 - 所有变量都在一次调用中翻转,没有那么大惊小怪。我需要知道的是我的概念是否真的安全。手动固定所有内容将是一个巨大的痛苦 - 我是否提到过这些结构很大?

固定一个变量是否会固定整个结构并使这种诡计成为可能,或者我只是幸运地到目前为止还没有占用内存?到目前为止,我的测试结果是肯定的,但我不能肯定地说。我宁愿不要让这件事发生在我身上。

【问题讨论】:

  • 欢迎来到 Stack Overflow!请不要包含有关问题标题中使用的语言的信息,除非没有它就没有意义。标记用于此目的。
  • 如果允许更改非托管缓冲区中的数据,您也可以在编组之前使用IntPtr.ToPointer()

标签: c# pinning


【解决方案1】:

据我所知,没有任何资源可以告诉您在 C# 中这样做是安全的。但是你会侥幸逃脱,GC 中没有任何机制可以保持 struct 的字段被固定并仍然允许 struct 中的其他字段移动。像这样的 fixed 语句会创建一个固定的 interior 指针,GC 足够聪明,可以从中发现对象根。内部指针只在 C++/CLI 的文献中被提及,这是一种允许直接使用 interior_ptr<> 关键字声明的语言。请注意,这在另一个 CLR 实现(如 Mono)上不一定能很好地工作。 YMMV。 C++/CLI 是更好的武器,至少您可以使用原始的 C 或 C++ 声明,而无需在 C# 中重写它。而且您将拥有一个指向本机结构的稳定指针。

首先这不应该是一个问题,只有当结构是在 GC 堆上分配的引用类型的一部分时才需要实际的对象固定。不知道您的代码是什么样的,但一种理智的方法是将这样的结构作为局部变量保留在读取和转换数据的方法中。此类值类型在堆栈上分配并具有稳定的地址。

请注意,这段代码中存在大量不安全,编译器和运行时都无法对您错误地使用魔法 32 值做任何事情。优化文件数据转换代码很少有用,读取数据的成本比解释数据高几个数量级。如此之多以至于使用反射来查找字段是合理的,你永远不会弄错。 Jon Skeet 的 EndianBinaryReader 也应该被提及。

【讨论】:

  • 我确实考虑过 C++/CLI,但话又说回来,虽然我对 C# 非常了解并且在 C++ 方面还过得去,但那是完全不同的动物。我想避免只为整个项目的一个特定部分学习一门新语言。至于 EndianBinaryReader - 我特别试图通过将其作为一个块读取来避免这种情况。我的结构中有很多很多字段和数组,因此使用 BinaryReader 中的任何内容都非常乏味和耗时。我开始这样做,但很快改变了主意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 2011-02-22
相关资源
最近更新 更多