Due to their nature, pointers produce unverifiable code. Thus, usage of any pointer type requires an
System.IntPtr is a safe wrapper around a
void*. It is intended as a more convenient alternative to
void* when an unsafe context isn't otherwise required to perform the task at hand.
Like in C and C++, incorrect usage of pointers can invoke undefined behavior, with possible side-effects being memory corruption and execution of unintended code. Due to the unverifiable nature of most pointer operations, correct usage of pointers is entirely a responsibility of the programmer.
Types that support pointers
Unlike C and C++, not all C# types have corresponding pointer types. A type
T may have a corresponding pointer type if both of the following criteria apply:
Tis a struct type or a pointer type.
Tcontains only members that satisfy both of these criteria recursively.
The criteria that a type must satisfy in order to support pointers (see Remarks) cannot be expressed in terms of generic constraints. Therefore, any attempt to declare a pointer to a type provided through a generic type parameter will fail.
Member access using ->
C# inherits from C and C++ the usage of the symbol
-> as a means of accessing the members of an instance through a typed pointer.
Consider the following struct:
This is an example of the usage of
-> to access its members:
Addition and subtraction in pointers works differently from integers. When a pointer is incremented or decremented, the address it points to is increased or decreased by the size of the referent type.
For example, the type
int (alias for
System.Int32) has a size of 4. If an
int can be stored in address 0, the subsequent
int can be stored in address 4, and so on. In code:
Similarly, the type
long (alias for
System.Int64) has a size of 8. If a
long can be stored in address 0, the subsequent
longcan be stored in address 8, and so on. In code:
void is special and
void pointers are also special and they are used as catch-all pointers when the type isn't known or doesn't matter. Due to their size-agnostic nature,
void pointers cannot be incremented or decremented:
Pointers for array access
This example demonstrates how pointers can be used for C-like access to C# arrays.
unsafe keyword is required because pointer access will not emit any bounds checks that are normally emitted when accessing C# arrays the regular way.
fixed keyword tells the C# compiler to emit instructions to pin the object in an exception-safe way. Pinning is required to ensure that the garbage collector will not move the array in memory, as that would invalidate any pointers pointing within the array.
The asterisk is part of the type
In C and C++, the asterisk in the declaration of a pointer variable is part of the expression being declared. In C#, the asterisk in the declaration is part of the type.
In C, C++ and C#, the following snippet declares an
In C and C++, the following snippet declares an
int pointer and an
int variable. In C#, it declares two
In C and C++, the following snippet declares two
int pointers. In C#, it is invalid:
C# inherits from C and C++ the usage of
void* as a type-agnostic and size-agnostic pointer.
Any pointer type can be assigned to
void* using an implicit conversion:
The reverse requires an explicit conversion: