Вы находитесь на странице: 1из 13

Pointers

and Low-Level Programming

© University of Linz, Institute for System Software, 2004


published under the Microsoft Curriculum License
1
Pointer Types
Examples
ip int
int* ip; // pointer to an int cell
sp
MyStruct* sp; // pointer to a MyStruct object MyStruct
void* vp; // pointer to any memory location vp
int** ipp; // pointer to a pointer to an int cell
ipp

int

Syntax
PointerType = UnmanagedType "*" pointers to arbitrary types
| "void" "*".
UnmanagedType = ValueType if a struct type, all fields must be of an
| PointerType. UnmanagedType

• pointers are not traced by the garbage collector (referenced objects are not collected)
• pointer types are not compatible with System.Object
• pointer variables can have the value null
• pointers of different types can be compared with each other (==, !=, <, <=, >, >=)

2
Unsafe Code
Code that works with pointers is potentially unsafe
(can break type rules and destroy arbitrary memory locations)

• must be enclosed in an unsafe block or an unsafe method

unsafe { unsafe void foo() {


int* p; int* p;
... ...
} }

• must be compiled with the unsafe option

csc -unsafe MyProg.cs

• system administrator must assign FullTrust rights to the program

3
Using Pointers
Dereferencing a pointer
var
int var; ip *ip = 5;
int* ip = &var; int x = *ip;
• if v is of type T*, *v is of type T
• void* cannot be dereferenced

Access to struct fields


b
struct Block { int x, y, z; } bp x bp->x = 1; // pointer notation
Block b; y (*bp).y = 2 // alternatively
Block* bp = &b; z
• bp must be of type Block*
• works also for method calls

Access to array elements


a
int[] a = new int[3]; ap 0 ap[0] = 1; // array notation
int* ap = a; 1 *(ap+1) = 2 // alternatively
2
• no index bound checks!
works only in
ap[3] would be accepted
"fixed" statement
4
Address Arithmetic
Pointers can be used in calculations
T
T* p = ...;

T T
p++; // increases p by sizeof(T)
p--;
p

T T T
T* q, r;
q = p + 2; // q = p + 2*sizeof(T)
r = p - 1; // r = p - sizeof(T)
r p q

No pointer arithmetic with void*

5
Type Casts On Pointers
int i;
int* ip;
Block* bp;
void* vp;

Implicit Casts Explicit Casts


(without cast operator) (with cast operator)

T* ⇐ null ip = null; T1* ⇔ T2* ip = (int*)vp; unchecked!


bp = null; vp = (void*)ip;
vp = null; bp = (Block*)vp;

void* ⇐ T* vp = ip; T* ⇔ intType ip = (int*)i;


vp = bp; bp = (Block*)i;
vp = (void*)i;
i = (int)ip;
i = (int)bp;
i = (int)vp;

6
Pinned and Unpinned Variables
Pinned cannot be moved by the garbage collector
• local variables
• value parameters
• fields of pinned structs

Unpinned can be moved by the garbage collector


• fields of classes (also static fields)
• array elements
• ref and out parameters

7
Adress Operator
&designator yields the address of designator

Note
• designator must denote a pinned variable (e.g. &x, &s.f)
• the type of the variable must be unmanaged (i.e. no class, no array)
• if designator is of type T, &designator is of type T*

8
fixed Statement
Pins an unpinned variable during the execution of this statement
(i.e. the garbage collector cannot move it during this statement)

Syntax
FixedStat = "fixed" "(" PointerType FixedVarDecl {"," FixedVarDecl} ")" Statement.
FixedVarDecl = ident "="
( "&" UnpinnedVar • UnpinnedVar must be of an unmanaged type T
• T* must be assignable to PointerType
| ArrayVar • array elements must be of an unmanaged type T
• T* must be asignable to PointerType

| StringVar • char* must be assignable to PointerType


).
Examples
int field; fixed (int* p = &field) { ... }
int[] a = new int[10]; fixed (int* p = &a[1]) {...}
Person person = new Person(); fixed (int* p = &person.id) {...}
string s = "Hello"; fixed (int* p = a) {...}
fixed (char* p = s) {...}

Variables that are declared in the header of a fixed statement


9
are read-only
Examples
Printing the bytes of an int variable
x
int x = 3;
3 0 0 0
unsafe {
byte* p = (byte*) &x; p
for (int i = 0; i < 4; i++) { Console.Write("{0:x2} ", *p); p++; }
}

String processing
s
string s = "Hello";
H e l l o \0
unsafe {
fixed (char* p = s) { p
for (int i = 0; p[i] != '\0'; i++) Console.Write(p[i]);
}
}

10
Examples (continued)
Overlaying a byte array with a struct type
struct Block {
int x;
float f;
int y;
}
...
byte[] buffer = new byte[1024];
...
unsafe {
fixed (byte* bp = &buffer[3]) {
Block* b = (Block*) bp;
Console.WriteLine(b->x + " " + b->f + " " + b->y);
}
}

x f y
buffer

11
Dangers of Pointer Processing
Can destroy arbitrary memory locations
int[] a = new int[3];
unsafe {
fixed (int* p = a) { p[5] = 0; }
}

One can be left with pointers to objects that are moved by the garbage collector
int[] a = new int[5];
unsafe { q p
int* p;
fixed (int* q = a) { p = q + 2; } a
...
... // GC can move the array now
*p = 5; // destroys data
} p

12
Dangers of Pointer Processing (cont.)
One can be left with pointers to non-existing local variables
static unsafe int* Foo() {
int local = 3;
return &local;
}

static unsafe void Main() {


int* p = Foo();
...
*p = 5; // accesses non-existing local variable!
}

Therefore
Avoid pointer processing!
Unless you really need it for system-level programming

13

Вам также может понравиться