In exceptional
cases, your requirement might demand you to use pointers in your C# code.
When you use pointers, the corresponding block of code becomes unsafe.
In unsafe block you perform memory allocation in stack and not in heap.
But there are chances that you might access an existing reference type
of managed code inside unmanaged code. In such cases, you use fixed statement
in unsafe block while accessing managed resources. Fixed statement is
used in two different perspectives. They are mentioned below:
To
deal with fixed size buffers
To prevent the managed resource from being relocated by the garbage
collector
Fixed Size
Buffers: Assume that you have a structure containing an integer array
as its member. How do you declare it? Here is an example:
public struct
sampleStruct {
public int[] sampleArray;
}
Is there
any option to define and use fixed size arrays in C#? Yes. You can do
it using fixed statement. For that, you have to define the structure inside
unsafe code block. Here is the modified code sample:
unsafe {
public struct sampleStruct {
public fixed int sampleArray[300];
}
}
This sampleArray
is termed as unsafe buffer and not array. This unsafe buffer has certain
restrictions which are mentioned below:
Unsafe
Buffers can only be used inside a structure defined in unsafe code context
Unsafe buffer can only be a one dimensional array or a vector
You should always specify the keyword fixed along with the unsafe
buffer and the element should always associate a size along with it.
Fixed Statements
to lock Managed Variables: Assume that you access a reference type (managed)
inside your unsafe code block. If there is a fragmentation, garbage collector
can relocate the reference type to gather a block of continuous memory.
This will not have any implication in managed code since you do not access
memory directly.
But when
you use pointers in unsafe code to access that reference type, if the
reference type is relocated by the garbage collector then the pointer
will either point to an incorrect element in memory or the pointer might
become a dangling reference. To avoid this problem, you mark the pointer
accessing that reference type as fixed. By doing so, garbage collector
cannot pick the reference type for relocation. It has to wait until the
unsafe code block releases it. Here is a simple example demonstrating
the usage of fixed statements:
class sampleClass
{
public int member1;
public sampleClass(int member1) {
this.member1 = member1;
}
}
class testClass {
public static void Main(){
sampleClass obj = new sampleClass(100);
unsafe {
fixed(int* ptr2Member1 = &obj.member1) {
* ptr2Member1 = 500;
}
}
Console.WriteLine(Value of member1 is: {0}, obj.member1);
}
}
Output of
this code will be:
Value of
member1 is: 500
In this example,
you have accessed single instance field of a class using fixed statement.
You can also access multiple variables of the same type using multiple
pointers inside a single fixed statement. This is demonstrated using the
code sample below:
class sampleClass
{
public int member1, member2;
public sampleClass(int member1, int member2) {
this.member1 = member1;
this.member2 = member2;
}
}
class testClass {
public static void Main(){
sampleClass obj = new sampleClass(100, 200);
unsafe {
fixed(int* ptr1 = &obj.member1, ptr2 = & obj.member2) {
*ptr1 = 500;
*ptr2 = 800;
}
}
Console.WriteLine(member1 = {0}, member2 = {1} , obj.member1,
obj.member2);
}
}
Output of
this code will be:
member1 =
500, member2 = 800
In the above
example, you are using a single fixed statement to lock multiple variables
of the same type. What if you want to lock two variables of different
type? Then you have to use two fixed statements nested within one another
as shown below:
class sampleClass
{
public int member1;
public double member2;
public sampleClass(int member1, double member2) {
this.member1 = member1;
this.member2 = member2;
}
}
class testClass {
public static void Main(){
sampleClass obj = new sampleClass(100, 20.5);
unsafe {
fixed(int* ptr1 = &obj.member1) {
fixed(double* ptr2 = & obj.member2) {
*ptr1 = 500;
*ptr2 = 80.9;
}
}
}
Console.WriteLine(member1 = {0}, member2 = {1} , obj.member1,
obj.member2);
}
}
Output of
this code will be:
member1 =
500, member2 = 80.9
Not just
an instance member of a class, you can access an array or a string using
pointers inside fixed statements as well.