【问题标题】:How to get a pointer to memory of Array instance?如何获取指向 Array 实例内存的指针?
【发布时间】:2021-01-02 01:20:40
【问题描述】:

网上有很多示例如何获取指向byte[]int[,] 的指针,即当您确切知道数组的元素类型和等级时。但是如何获取泛型Array 的指针呢?

这里的主要问题是我不知道提前排名。我也不知道元素类型,但我知道只能有原始数字类型(在我的情况下),所以我可以输入一些额外的 ifs 来应对它。

背景:我想让这个解决方案https://stackoverflow.com/a/52750659/6734314 更通用——在它目前的形式下,它只适用于double[,],所以给出了经典的等级+类型:

double[,] doubles =  {
     { 1, 2, 3, 4 },
     ...
};
fixed (double* p = doubles)
{
  ...

第一次尝试

从 Olivier 的回答中,所有的错误都是我的。

Array data = new float[,] { { 4, 2 }, { 77, 3 } };
var reference = __makeref(data);
IntPtr pointer = **(IntPtr**)(&reference);

float* ptr = (float*)pointer.ToPointer();
{
  for (int i = 0; i < data.LongLength; ++i)
    Console.WriteLine(ptr[i]);
}

【问题讨论】:

  • 那么,数组中的指针总是第一个元素的地址,你能得到吗?如果您对数组一无所知,您如何获得数组,作为对象或其他东西?
  • 注意:大多数情况下,您以这种方式获得了指针,您需要非常非常小心 - 不能真正使用该指针 很多,因为只要它是非托管指针(而不是托管指针),在“固定”区域或引脚之外:你不能相信对象仍然存在(它可以随时移动)
  • @MarcGravell,是的,谢谢,这是我的想法,最后我找到了所有的片段(见我的帖子答案),我现在在阅读时使用固定记忆。

标签: c# arrays pointers


【解决方案1】:

组合:

Memory address of an object in C#

How can I display a pointer address in C#?

写作:

Array array = Array.CreateInstance(typeof(int), 10);
unsafe
{
  var reference = __makeref(array);
  var pointer = **(IntPtr**)( &reference );
  Console.WriteLine("0x{0:x}", (ulong)&reference);
  Console.WriteLine("0x{0:x}", (long)&reference);
  Console.WriteLine("0x{0:x}", (ulong)pointer);
  Console.WriteLine("0x{0:x}", (long)pointer);
}

输出:

0x8cb87af070
0x8cb87af070
0x1a9c1c46290
0x1a9c1c46290

Source code of Array class

【讨论】:

  • 非常感谢 +1,但我看不出它是如何工作的——请参阅我更新的问题,我应该看到值,但我没有。要么内存被移动,要么指针显示其他位置,而不是数组的数据内存。
【解决方案2】:

如果数据总是相同的形状(例如,二维矩形数组),但可能不同的类型,那么您或许可以使用T : unmanaged 约束和fixed 关键字:

    static void Main()
    {
        // sample taken from comtrade91.pdf section 6.6
        var data = new float[,] { { 4, 2 }, { 77, 3 } };
        ShowAddressAndData(data);
    }
    static unsafe void ShowAddressAndData<T>(T[,] data) where T : unmanaged
    {
        fixed(T* ptr = data)
        {
            Console.WriteLine((IntPtr)ptr);
            for (int i = 0; i < data.Length; i++)
            {
                Console.WriteLine(ptr[i]);
            }
        }
    }
    // this extra method just to show that we can overload on dimension
    static unsafe void ShowAddressAndData<T>(T[] data) where T : unmanaged
    {
        fixed (T* ptr = data)
        {
            Console.WriteLine((IntPtr)ptr);
            //..
        }
    }

【讨论】:

    【解决方案3】:

    我想我找到了,如果您发现一些太脆弱/可疑的东西,请发表评论:

    Array data = new float[,] { { 4, 2 }, { 77, 3 } };
    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
    try
    {
      IntPtr address = handle.AddrOfPinnedObject();
    
      float* ptr = (float*)address.ToPointer();
      for (int i = 0; i < data.LongLength; ++i)
        Console.WriteLine(ptr[i]);
    }
    finally
    {
      handle.Free();
    }
    

    【讨论】:

    • 对我来说看起来很棒;但是,问题是:如果不是类型,数组是否至少可以在 shape 中预测?如果泛型总是(比如)T[,](某些类型为T 的二维数组),那么您还可以使用泛型做一些事情。注意:您应该可能在此处使用try/finally,以便句柄始终处于空闲状态,即使在失败情况下也是如此
    • @MarcGravell,关于最后的好点,以坏习惯公开是没有意义的。在我的例子中,形状(等级)可以是任何东西,类型可以是基本数字类型之一——字节、sbyte、int 等。
    猜你喜欢
    • 2014-08-21
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多