Bagaimana cara mendapatkan pointer ke memori instance Array?

Sep 15 2020

Ada banyak contoh di internet bagaimana mendapatkan pointer ke byte[]or int[,], yaitu ketika Anda tahu persis jenis elemen dan peringkat array. Tetapi bagaimana cara mendapatkan pointer untuk generik Array?

Masalah utama di sini adalah saya tidak tahu peringkat sebelumnya. Saya tidak tahu tipe elemen juga tapi saya tahu hanya ada tipe numerik primitif (dalam kasus saya), jadi saya bisa mengetik beberapa tambahan ifuntuk mengatasinya.

Latar Belakang: Saya ingin membuat solusi ini https://stackoverflow.com/a/52750659/6734314lebih umum - dalam bentuknya saat ini ia hanya berfungsi dengan double[,]begitu tipe rank + klasik diberikan:

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

Percobaan pertama

Dari jawaban Olivier, semua kesalahan adalah milik saya.

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

Jawaban

3 OlivierRogier Sep 15 2020 at 16:52

Menggabungkan:

Alamat memori suatu objek di C #

Dan

Bagaimana cara menampilkan alamat penunjuk di C #?

Penulisan:

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

Keluaran:

0x8cb87af070
0x8cb87af070
0x1a9c1c46290
0x1a9c1c46290

Kode sumber kelas Array

2 MarcGravell Sep 15 2020 at 19:27

Jika datanya selalu dalam bentuk yang sama (misalnya, larik persegi panjang 2D), tetapi kemungkinan jenisnya berbeda , Anda mungkin dapat menggunakan T : unmanagedbatasan dan fixedkata kunci:

    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);
            //..
        }
    }
1 astrowalker Sep 15 2020 at 18:57

Saya rasa saya menemukannya, beri komentar jika Anda menemukan sesuatu yang terlalu rapuh / mencurigakan:

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