Csharp/C Sharp/Language Basics/Unsafe Code

Материал из .Net Framework эксперт
Перейти к: навигация, поиск

Accessing Structure Members with a Pointer

using System;
   
public struct Point2D {
    public int X;
    public int Y;
}
   
public class MyClass {
    public unsafe static void Main() {
        Point2D MyPoint;
        Point2D * PointerToMyPoint;
   
        MyPoint = new Point2D();
        PointerToMyPoint = &MyPoint;
        PointerToMyPoint->X = 100;
        PointerToMyPoint->Y = 200;
        Console.WriteLine("({0}, {1})", PointerToMyPoint->X, PointerToMyPoint->Y);
    }
}


Address and size of pointer object

 
using System;
class MainEntryPoint {
    static unsafe void Main() {
        int x = 10;
        short y = -1;
        byte y2 = 4;
        double z = 1.5;
        int* pX = &x;
        short* pY = &y;
        double* pZ = &z;
        Console.WriteLine("Address of x is 0x{0:X}, size is {1}, value is {2}",(uint)&x, sizeof(int), x);
        Console.WriteLine(
            "Address of y is 0x{0:X}, size is {1}, value is {2}",
            (uint)&y, sizeof(short), y);
        Console.WriteLine(
            "Address of y2 is 0x{0:X}, size is {1}, value is {2}",
            (uint)&y2, sizeof(byte), y2);
        Console.WriteLine(
            "Address of z is 0x{0:X}, size is {1}, value is {2}",
            (uint)&z, sizeof(double), z);
        Console.WriteLine(
            "Address of pX=&x is 0x{0:X}, size is {1}, value is 0x{2:X}",
            (uint)&pX, sizeof(int*), (uint)pX);
        Console.WriteLine(
            "Address of pY=&y is 0x{0:X}, size is {1}, value is 0x{2:X}",
            (uint)&pY, sizeof(short*), (uint)pY);
        Console.WriteLine(
            "Address of pZ=&z is 0x{0:X}, size is {1}, value is 0x{2:X}",
            (uint)&pZ, sizeof(double*), (uint)pZ);
        *pX = 20;
        Console.WriteLine("After setting *pX, x = {0}", x);
        Console.WriteLine("*pX = {0}", *pX);
        pZ = (double*)pX;
        Console.WriteLine("x treated as a double = {0}", *pZ);
        Console.ReadLine();
    }
}


Allocating Memory from the Stack

using System;
   
public class MyClass
{
    public unsafe static void Main()
    {
        int * buf = stackalloc int [5];
   
        for(int i = 0; i < 5; i++)
            buf[i] = i;
        for(int i = 0; i < 5; i++)
            Console.WriteLine(buf[i]);
    }
}


Fixing Managed Data in Memory

using System;
   
public class MyClass
{
    public unsafe static void Main()
    {
        int i;
        int [] intArr;
   
        intArr = new int [5];
        fixed(int * IntegerPointer = intArr)
        {
            for(i = 0; i < 5; i++)
                IntegerPointer[i] = i;
        }
        for(i = 0; i < 5; i++)
            Console.WriteLine(intArr[i]);
    }
}


Get variable address in unsafe mode

 
using System;
public class MainEntryPoint {
    public static unsafe void Main() {
        Console.WriteLine("Size of Currency struct is " + sizeof(MyStruct));
        MyStruct amount1, amount2;
        MyStruct* pointerStruct = &amount1;
        long* pDollars = &(pointerStruct->Dollars);
        byte* pCents = &(pointerStruct->Cents);
        Console.WriteLine("Address of amount1 is 0x{0:X}", (uint)&amount1);
        Console.WriteLine("Address of amount2 is 0x{0:X}", (uint)&amount2);
        Console.WriteLine("Address of pAmt is 0x{0:X}", (uint)&pointerStruct);
        Console.WriteLine("Address of pDollars is 0x{0:X}", (uint)&pDollars);
        Console.WriteLine("Address of pCents is 0x{0:X}", (uint)&pCents);
        pointerStruct->Dollars = 20;
        *pCents = 50;
        Console.WriteLine("amount1 contains " + amount1);
        --pointerStruct;   
        Console.WriteLine("amount2 has address 0x{0:X} and contains {1}",
           (uint)pointerStruct, *pointerStruct);
        MyStruct* pTempCurrency = (MyStruct*)pCents;
        pCents = (byte*)(--pTempCurrency);
        Console.WriteLine("Address of pCents is now 0x{0:X}", (uint)&pCents);
        Console.WriteLine("\nNow with classes");
        MyClass amount3 = new MyClass();
        fixed (long* pDollars2 = &(amount3.Dollars))
        fixed (byte* pCents2 = &(amount3.Cents)) {
            Console.WriteLine("amount3.Dollars has address 0x{0:X}", (uint)pDollars2);
            Console.WriteLine("amount3.Cents has address 0x{0:X}", (uint)pCents2);
            *pDollars2 = -100;
            Console.WriteLine("amount3 contains " + amount3);
        }
    }
}
struct MyStruct {
    public long Dollars;
    public byte Cents;
    public override string ToString() {
        return "$" + Dollars + "." + Cents;
    }
}
class MyClass {
    public long Dollars;
    public byte Cents;
    public override string ToString() {
        return "$" + Dollars + "." + Cents;
    }
}


int pointer variable

 
using System;
public class MainClass {
    static void Main(string[] args) {
        unsafe {
            int variable = 10;
            int* pVariable = &variable;
            Console.WriteLine("Value at address is {0}.", *pVariable);
        }
    }
}


mark method as unsafe

 
class FixedArrayApp
{
    unsafe public static void Foo(int* pa)
    {
        for (int* ip = pa; ip < (pa+5); ip++)
        {
            Console.Write("{0,-3}", *ip);
        }
    }
   
    static void Main(string[] args)
    {
        int[] ia = new int[5]{12,34,56,78,90};
   
        unsafe
        {
            fixed (int* pa = ia)
            {
                Foo(pa);
            }
        }
    }
}


object pointer

 
using System;
public struct MyValue
{
    public int id;
    private decimal price;
    public MyValue(int id, decimal price) 
    { 
        this.id = id; 
        this.price = price;
    }
    public void Foo() { Console.WriteLine("Foo"); }
}
   
class DerefMemberApp
{
    static void Main(string[] args)
    {
        MyValue i = new MyValue(123, 45.67m);
   
        unsafe
        {
            MyValue* pi = &i;
            (*pi).Foo();
            pi->Foo();
   
            Console.WriteLine("id = {0}", pi->id);
        }
    }
}


Supported sizeof() Types

Expression           Result
sizeof(sbyte)        1
sizeof(byte)         1
sizeof(short)        2
sizeof(ushort)       2
sizeof(int)          4
sizeof(uint)         4
sizeof(long)         8
sizeof(ulong)        8
sizeof(char)         2
sizeof(float)        4
sizeof(double)       8
sizeof(bool)         1


unsafe and fixed block

 
public class MyValue
{
    public int id;
    public MyValue(int id) { this.id = id; }
}
   
class UnsafeClassApp
{
    unsafe public static void Swap(int* pi, int* pj)
    {
        int tmp = *pi;
        *pi = *pj;
        *pj = tmp;
    }
   
    static void Main(string[] args)
    {
        MyValue i = new MyValue(123);
        MyValue j = new MyValue(456);
        Console.WriteLine("Before Swap:\ti = {0}, j = {1}", i.id, j.id);
   
        unsafe
        {
             (int* pi = &i.id, pj = &j.id)
            {
                Swap(pi, pj);
            }
        }
   
        Console.WriteLine(
            "After Swap:\ti = {0}, j = {1}", i.id, j.id);
    }
}


Unsafe code: get data type size

   using System;
   class MainEntryPoint
   {
      static unsafe void Main()
      {
         int x=100;
         short y = -19;
         byte y2 = 45;
         double z = 31.5;
         int *pX = &x;
         short *pY = &y;
         double *pZ = &z;
         Console.WriteLine("Address of x is 0x{0:X}, size is {1}, value is {2}", (uint)&x, sizeof(int), x);
         Console.WriteLine("Address of y is 0x{0:X}, size is {1}, value is {2}", (uint)&y, sizeof(short), y);
         Console.WriteLine("Address of y2 is 0x{0:X}, size is {1}, value is {2}",(uint)&y2, sizeof(byte), y2);
         Console.WriteLine("Address of z is 0x{0:X}, size is {1}, value is {2}", (uint)&z, sizeof(double), z);
         Console.WriteLine("Address of pX=&x is 0x{0:X}, size is {1}, value is 0x{2:X}",(uint)&pX, sizeof(int*), (uint)pX);
         Console.WriteLine("Address of pY=&y is 0x{0:X}, size is {1}, value is 0x{2:X}",(uint)&pY, sizeof(short*), (uint)pY);
         Console.WriteLine("Address of pZ=&z is 0x{0:X}, size is {1}, value is 0x{2:X}",(uint)&pZ, sizeof(double*), (uint)pZ);
         *pX = 20;
         Console.WriteLine("After setting *pX, x = {0}", x);
         Console.WriteLine("*pX = {0}", *pX);
         pZ = (double*)pX;
         Console.WriteLine("x treated as a double = {0}", *pZ);
      }
   }


Unsafe Methods

using System;
   
public class MyClass
{
    public unsafe static void Main()
    {
        int MyInteger = 123;
        int * MyIntegerPointer = &MyInteger;
   
        Console.WriteLine(*MyIntegerPointer);
    }
}


Use unsafe method to clone array

 
public struct MyValue
{
    public int id;
    public MyValue(int id) { this.id = id; }
}
class ClassAddressApp
{
    unsafe public static MyValue[] CloneMyValues(MyValue[] box)
    {
        MyValue[] ret = new MyValue[box.Length];
        fixed (MyValue* src = box, dest = ret)
        {
            MyValue* pSrc = src;
            MyValue* pDest = dest;
            for (int index = 0; index < box.Length; index++)
            {
                *pDest = *pSrc;
                pSrc++;
                pDest++;
            }
        }
        return ret;
    }
   
    static void Main(string[] args)
    {
        MyValue[] box = new MyValue[2];
        box[0] =  new MyValue(1);
        box[1] = new MyValue(2);
   
        MyValue[] bag = CloneMyValues(box);
        foreach (MyValue i in bag)
        {
            Console.WriteLine(i.id);
        }
    }
}


Use unsage code to swap two integers

 

public class TestUnsafeApp
{
    unsafe public static void Swap(int* pi, int* pj)
    {
        int tmp = *pi;
        *pi = *pj;
        *pj = tmp;
    }
   
    public static void Main(string[] args)
    {
        int i = 3;
        int j = 4;
        Console.WriteLine("BEFORE: i = {0}, j = {1}", i, j);
   
        unsafe { Swap(&i, &j); }
   
        Console.WriteLine("AFTER:  i = {0}, j = {1}", i, j);
    }
}


Using the unsafe keyword

using System;
class Test {
  public static unsafe String UnsafeCodeExample( String s ) {
    int strLength = s.Length;
    char[] str = new char[strLength+1];
    string strReturn = "";
    fixed(char* strPointer = str) {
      for ( int i=0; i<strLength; ++i )
        strReturn += strPointer[i];
    }
    return strReturn;
  }
  public static void Main() {
   String s = UnsafeCodeExample("This is a test");
   Console.WriteLine( "Reversed: {0}", s );
  }
}