Puntatori e codice non sicuro

Puntatori e codice non sicuro

# Introduzione al codice non sicuro

C# consente di utilizzare variabili puntatore in una funzione del blocco di codice quando è contrassegnato da unsafe modificatore. Il codice non sicuro o il codice non gestito è un blocco di codice che utilizza una variabile puntatore.

Un puntatore è una variabile il cui valore è l'indirizzo di un'altra variabile, cioè l'indirizzo diretto della locazione di memoria. simile a qualsiasi variabile o costante, devi dichiarare un puntatore prima di poterlo utilizzare per memorizzare qualsiasi indirizzo di variabile.

La forma generale di una dichiarazione di puntatore è:

type *var-name;

Di seguito sono riportate dichiarazioni di puntatore valide:

int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

L'esempio seguente illustra l'uso dei puntatori in C#, usando il modificatore unsafe:

using System;
namespace UnsafeCodeApplication
{
   class Program
   {
      static unsafe void Main(string[] args)
      {
         int var = 20;
         int* p = &var;
         Console.WriteLine("Data is: {0} ",  var);
         Console.WriteLine("Address is: {0}",  (int)p);
         Console.ReadKey();
      }
   }
}

Quando il codice sopra è stato compilato ed eseguito, produce il seguente risultato:

Data is: 20
Address is: 99215364

Invece di dichiarare non sicuro un intero metodo, puoi anche dichiarare non sicuro una parte del codice:

// safe code
unsafe
{
    // you can use pointers here
}
// safe code

# Accesso agli elementi dell'array utilizzando un puntatore

In C#, un nome di matrice e un puntatore a un tipo di dati come i dati di matrice non sono lo stesso tipo di variabile. Ad esempio, int *p e int[] p , non sono dello stesso tipo. Puoi incrementare la variabile del puntatore p perché non è fisso in memoria ma un indirizzo di array è fisso in memoria e non puoi incrementarlo.

Pertanto, se è necessario accedere ai dati di un array utilizzando una variabile puntatore, come facciamo tradizionalmente in C o C++, è necessario correggere il puntatore utilizzando la parola chiave fixed.

L'esempio seguente lo dimostra:

using System;
namespace UnsafeCodeApplication
{
   class TestPointer
   {
      public unsafe static void Main()
      {
         int[]  list = {10, 100, 200};
         fixed(int *ptr = list)
         
         /* let us have array address in pointer */
         for ( int i = 0; i < 3; i++)
         {
            Console.WriteLine("Address of list[{0}]={1}",i,(int)(ptr + i));
            Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
         }
         
         Console.ReadKey();
      }
   }
}

Quando il codice sopra è stato compilato ed eseguito, produce il seguente risultato:

Address of list[0] = 31627168
Value of list[0] = 10
Address of list[1] = 31627172
Value of list[1] = 100
Address of list[2] = 31627176
Value of list[2] = 200

# Compilazione di codice non sicuro

Per compilare codice non sicuro, devi specificare il /unsafe opzione della riga di comando con il compilatore della riga di comando.

Ad esempio, per compilare un programma denominato prog1.cs contenente codice non sicuro, dalla riga di comando, dai il comando:

csc /unsafe prog1.cs

Se stai usando Visual Studio IDE, devi abilitare l'uso di codice non sicuro nelle proprietà del progetto.

Per fare questo:

  • Apri le proprietà del progetto facendo doppio clic sul nodo delle proprietà in Esplora soluzioni.
  • - Fare clic sulla scheda Crea.
  • Seleziona l'opzione "Consenti codice non sicuro"
  • # Recupero del valore dei dati utilizzando un puntatore

    È possibile recuperare i dati archiviati nella posizione a cui fa riferimento la variabile puntatore, utilizzando il metodo ToString(). L'esempio seguente lo dimostra:

    using System;
    namespace UnsafeCodeApplication
    {
       class Program
       {
          public static void Main()
          {
             unsafe
             {
                int var = 20;
                int* p = &var;
                Console.WriteLine("Data is: {0} " , var);
                Console.WriteLine("Data is: {0} " , p->ToString());
                Console.WriteLine("Address is: {0} " , (int)p);
             }
             
             Console.ReadKey();
          }
       }
    }
    
    

    Quando il codice sopra è stato compilato ed eseguito, produce il seguente risultato:

    Data is: 20
    Data is: 20
    Address is: 77128984
    
    

    # Passaggio di puntatori come parametri ai metodi

    È possibile passare una variabile puntatore a un metodo come parametro. L'esempio seguente illustra questo:

    using System;
    namespace UnsafeCodeApplication
    {
       class TestPointer
       {
          public unsafe void swap(int* p, int *q)
          {
             int temp = *p;
             *p = *q;
             *q = temp;
          }
          
          public unsafe static void Main()
          {
             TestPointer p = new TestPointer();
             int var1 = 10;
             int var2 = 20;
             int* x = &var1;
             int* y = &var2;
             
             Console.WriteLine("Before Swap: var1:{0}, var2: {1}", var1, var2);
             p.swap(x, y);
    
             Console.WriteLine("After Swap: var1:{0}, var2: {1}", var1, var2);
             Console.ReadKey();
          }
       }
    }
    
    

    Quando il codice sopra viene compilato ed eseguito, produce il seguente risultato:

    Before Swap: var1: 10, var2: 20
    After Swap: var1: 20, var2: 10
    
    

    No