Sök…


Anmärkningar

Pekare och unsafe

På grund av sin natur producerar pekare overifierbar kod. Således kräver användning av vilken som helst pekartyp ett unsafe sammanhang.

Typen System.IntPtr är ett säkert omslag runt ett void* . Det är avsett som ett mer bekvämt alternativ till void* när ett osäkra sammanhang inte annars krävs för att utföra uppgiften.

Odefinierat beteende

Liksom i C och C ++ kan felaktig användning av pekare åberopa odefinierat beteende, med möjliga biverkningar är minneskorruption och exekvering av oavsiktlig kod. På grund av att de flesta pekareoperationer inte kan verifieras är korrekt användning av pekare helt ansvarig för programmeraren.

Typer som stöder pekare

Till skillnad från C och C ++ har inte alla C # -typer motsvarande pekartyper. En typ T kan ha en motsvarande pekartyp om båda följande kriterier gäller:

  • T är en strukturtyp eller en pekartyp.
  • T innehåller endast medlemmar som uppfyller båda dessa kriterier rekursivt.

Pekare för array-åtkomst

Detta exempel visar hur pekare kan användas för C-liknande åtkomst till C # -matriser.

unsafe
{
    var buffer = new int[1024];
    fixed (int* p = &buffer[0])
    {
        for (var i = 0; i < buffer.Length; i++)
        {
            *(p + i) = i;
        }
    }
}

Det unsafe nyckelordet krävs eftersom pekaråtkomst inte släpper ut några gränskontroller som normalt släpps ut när du använder C # -matriser på det vanliga sättet.

Det fixed nyckelordet berättar för C # -kompileraren att avge instruktioner för att fästa objektet på ett undantagssäkert sätt. Fästning krävs för att säkerställa att avfallssamlaren inte kommer att flytta matrisen i minnet, eftersom det skulle ogiltiga alla pekare som pekar i matrisen.

Pekare aritmetiska

Tillsats och subtraktion i pekare fungerar annorlunda än heltal. När en pekare ökas eller minskas ökar eller minskas adressen den pekar på med referensstorleken.

Exempelvis har typen int (alias för System.Int32 ) en storlek på 4. Om en int kan lagras i adress 0 kan den efterföljande int lagras i adress 4 och så vidare. I kod:

var ptr = (int*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr)); // prints 0
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 4
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 8

På liknande sätt har typen long (alias för System.Int64 ) en storlek på 8. Om en long kan lagras i adress 0, kan den efterföljande long lagras i adress 8, och så vidare. I kod:

var ptr = (long*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr)); // prints 0
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 8
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 16

Typen void är speciell och void pekare är också speciell och de används som catch-alla pekare när typen inte är känd eller spelar ingen roll. På grund av deras storlek-agnostiska karaktär, kan void pekare inte ökas eller minskas:

var ptr = (void*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr));
ptr++; // compile-time error
Console.WriteLine(new IntPtr(ptr));
ptr++; // compile-time error
Console.WriteLine(new IntPtr(ptr));

Asterisken är en del av typen

I C och C ++ är asterisken i deklarationen för en pekvariabel en del av uttrycket som deklareras. I C # är asterisken i deklarationen en del av typen .

I C, C ++ och C # förklarar följande utdrag en int pekare:

int* a;

I C och C ++ förklarar följande utdrag en int pekare och en int variabel. I C # förklarar det två int pekare:

int* a, b; 

I C och C ++ förklarar följande utdrag två int pekare. I C # är det ogiltigt:

int *a, *b;

tomhet*

C # ärver från C och C ++ användningen av void* som en typ-agnostisk och storlek-agnostisk pekare.

void* ptr;

Vilken som helst pekartyp kan tilldelas void* hjälp av en implicit konvertering:

int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;

Det omvända kräver en uttrycklig konvertering:

int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;
int* p2 = (int*)ptr;

Medlemsåtkomst med ->

C # ärver från C och C ++ användningen av symbolen -> som ett sätt att få åtkomst till medlemmarna i en instans genom en typpekare.

Tänk på följande struktur:

struct Vector2
{
    public int X;
    public int Y;
}

Detta är ett exempel på användningen av -> att få åtkomst till sina medlemmar:

Vector2 v;
v.X = 5;
v.Y = 10;

Vector2* ptr = &v;
int x = ptr->X;
int y = ptr->Y;
string s = ptr->ToString();

Console.WriteLine(x); // prints 5
Console.WriteLine(y); // prints 10
Console.WriteLine(s); // prints Vector2

Generiska pekare

De kriterier som en typ måste uppfylla för att stödja pekare (se anmärkningar ) kan inte uttryckas i form av generiska begränsningar. Därför misslyckas alla försök att förklara en pekare till en typ som tillhandahålls genom en generisk typparameter.

void P<T>(T obj) 
    where T : struct
{
    T* ptr = &obj; // compile-time error
}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow