C# Language
pekare
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. -
Tinnehå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
}