C # небезопасный код исправлен указатель передан в качестве параметра - PullRequest
7 голосов
/ 11 ноября 2011

Я обнаружил следующий код в msdn:

        unsafe static void SquarePtrParam (int* p) 
        {
            *p *= *p;
        }

        unsafe static void Main() 
        {
            Point pt = new Point();
            pt.x = 5;
            pt.y = 6;
            // Pin pt in place:
            fixed (int* p = &pt.x) 
            {
                SquarePtrParam (p);
            }
            // pt now unpinned.
            Console.WriteLine ("{0} {1}", pt.x, pt.y);
        }

Мне просто интересно, мы напрямую обращаемся к указателю в функции SquarePtrParam, наследует ли она информацию о том, что массив исправлен из вызывающего метода?

Почему бы нам не установить явное значение fixed локально в SquarePtrParam.

Полагаю, я мог бы использовать некоторые уточнения относительно этого оператора fixed.

Ответы [ 2 ]

5 голосов
/ 11 ноября 2011

Исправлена ​​ошибка, из-за которой оператор «unpin» реализовывал область памяти таким же образом, что и оператор «using», закрывающий открытые файлы при использовании конструкции (FileStream stream = new FileStream (..)).Память будет закреплена до тех пор, пока вы не покинете фиксированный блок кода.

В коде IL он создаст фиктивную локальную переменную PINNED и сохранит в ней указатель.Это не позволит GC перемещать область памяти, содержащую этот указатель.После того, как вы покинете фиксированный блок, он будет хранить ноль в этой переменной PINNED.Просто так:

public static unsafe void TestInternal(byte* pointer)
{
    Console.WriteLine((IntPtr)pointer);
}

public static void FixedDemo()
{
    Byte[] newArray = new Byte[1024];

    unsafe
    {
        fixed (Byte* pointer = &newArray[0])
        {
            TestInternal(pointer);
        }
    }

    Console.WriteLine("Test Complete");
}

Так что FixedDemo в IL Code:

.method public hidebysig static void  FixedDemo() cil managed
{
  // Code size       47 (0x2f)
  .maxstack  2
  .locals init ([0] uint8[] newArray,
           [1] uint8& pinned pointer)
  IL_0000:  nop
  IL_0001:  ldc.i4     0x400 // Put 1024 on the stack
  IL_0006:  newarr     [mscorlib]System.Byte // allocate new array of 1024 length
  IL_000b:  stloc.0    // Store it in local variable 0
  IL_000c:  nop 
  IL_000d:  ldloc.0    // Put local variable 0 on the stack
  IL_000e:  ldc.i4.0   // Put zero on the stack
  IL_000f:  ldelema    [mscorlib]System.Byte // Load address of zero index from array
  IL_0014:  stloc.1    // !!! Here we pin memory by storing it in pinned variable
  IL_0015:  nop
  IL_0016:  ldloc.1    // Load function argument
  IL_0017:  conv.i     // Perform conversion 
  IL_0018:  call       void FinMath.Tests.Program::TestInternal(uint8*)
  IL_001d:  nop
  IL_001e:  nop
  IL_001f:  ldc.i4.0   // Load zero on the stack
  IL_0020:  conv.u     // Perform conversion 
  IL_0021:  stloc.1    // !!!! Here we unpin memory
  IL_0022:  nop
  IL_0023:  ldstr      "Test Complete" // Load string
  IL_0028:  call       void [mscorlib]System.Console::WriteLine(string) // Out message
  IL_002d:  nop
  IL_002e:  ret
} // end of method Program::FixedDemo

Для получения дополнительной информации посетите:

  1. MSDN

  2. MSDN Magazine: Сборка мусора: автоматическое управление памятью в Microsoft .NET Framework

  3. Общий язык Стандарт выполнения ECMA 335 Раздел III, 1.1.4.2 Управляемый указатель (тип &)

1 голос
/ 11 ноября 2011

наследует ли информация, что массив исправлен из вызывающего метода?

Нет, эта информация не нужна. Все, что он знает, это то, что ему передали указатель. Один из способов получения указателя - с помощью оператора fixed, но есть и другие способы (например, путем преобразования IntPtr), и любые такие совместимые указатели также могут быть переданы в SquarePtrParam.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...