c#中unsafe关键字

参考:https://jingyan.baidu.com/article/c910274ba8d1adcd371d2d4c.html

(1)unsafe 和 fixed

unsafe
{               
    int[] array = new int[10];
    for (int i = 0; i < array.Length; i++)
    {
        array[i] = i;
    }
    fixed (int* p = array)    //如果要获取变量的指针,需要放入fixed语句获取指针
    {
        for (int i = 0; i < array.Length; i++)
        {
            System.Console.WriteLine(p[i]);
        }                    
    }               
}

指针在c#中是不提倡使用的,有关指针的操作被认为是不安全的(unsafe)。因此运行这段代码之前,先要改一个地方,否则编译不过无法运行。
修改方法:在右侧的解决方案中找到你的项目文件,在项目图标(绿色)上点右键,选最后一项properties,然后在生成标签页里把Allow unsafe code勾选上,之后这段代码可以像C语言那样用指针操纵数组运行。

前提是必须有fixed (int* p = array),它的意思是如果要获取变量array的指针让p固定指向数组array,不允许改动。因为C#的自动垃圾回收机制会允许已经分配的内存在运行时进行位置调整,如果那样,p可能一开始指的是array,但后来array的位置被调整到别的位置后,p指向的就不是array了。所以要加一个fixed关键字,把它定在那里一动不动,之后的操作才有保障。

另有两点需要注意:

1)指针的使用必须放在unsafe的区域里;unsafe关键字也可作为类或方法的修饰符。

2)fixed (int* p = array)中,p的定义不能写在别处,而且fixed关键字也只能在unsafe区域里使用。

略简洁的unsafe写法

    class Program
    {
        unsafe public static UInt16 Htons(UInt16 src) 
        {
            UInt16 dest;
            // 不能照搬C的源代码,因为有些类型长度不一样,如C#中char(2字节),long(8字节)
            // ((char*)&dest)[0] = ((char*)&src)[1];
            // ((char*)&dest)[1] = ((char*)&src)[0];
            ((byte*)&dest)[0] = ((byte*)&src)[1];
            ((byte*)&dest)[1] = ((byte*)&src)[0];
            return dest;
        }

        public static UInt16 ConciseHtons(UInt16 src) 
        {
            UInt16 dest;
            unsafe
            {
                ((byte*)&dest)[0] = ((byte*)&src)[1];
                ((byte*)&dest)[1] = ((byte*)&src)[0];
            }            
            return dest;
        }
        
        static void Main() 
        {
            UInt16 val = 1;

            // 如果方法是unsafe的,则必须在unsafe block里调用
            unsafe
            {                
                val = Htons(val);
            }
            Console.WriteLine(val);

            // 更简洁的写法是把unsafe block写在函数内部
            val = ConciseHtons(val);
            Console.WriteLine(val);
        }                
    }
(2)C#在调用一些API和别的程序模块时,也常常需要指针。C#有一个类型IntPtr,常用来传递指针类型

(3) stackalloc

stackalloc的用处仅仅是把数组分配在栈上(默认是分配在托管堆上的)。

    class MyClass
    {
        public int val;
    }

    class Program
    {                
        static void Main() 
        {            
            unsafe
            {                
                MyClass *p = stackalloc MyClass[1]; // Error!! 如果类型要放在托管堆上则不行,如果MyClass是struct就OK了
                p->val = 1;

                int *iArray = stackalloc int[100];  // OK,在栈上创建数组, int类型本身就是放在栈上的
            }            
        }                
    }
 

注意:指针指向的内存一定要固定。凡是C#里的引用类型(一切类型的数组都是引用类型)都是分配在托管堆上的,都不固定。有两种方法强制固定,一种是用stackalloc分配在栈上,另一种是用fixed分配在堆上

猜你喜欢

转载自blog.csdn.net/ABC13222880223/article/details/88807505