• C# unsafe code


    (*) unsafe 和 fixed

    复制代码
    unsafe
    {               
        
    int[] array = new int[10];
        
    for (int i = 0; i < array.Length; i++)
        {
            array[i] 
    = i;
        }
        
    fixed (int* p = array) 
        {
            
    for (int i = 0; i < array.Length; i++)
            {
                System.Console.WriteLine(p[i]);
            }                    
        }               
    }
    复制代码


    指针在c#中是不提倡使用的,有关指针的操作被认为是不安全的(unsafe)。因此运行这段代码之前,先要改一个地方,否则编译不过无法运行。
    修改方法:在右侧的solution Explorer中找到你的项目,在项目图标(绿色)上点右键,选最后一项properties,然后在Build标签页里把Allow unsafe code勾选上。之后这段代码就可以运行了,你会看到,上面这段代码可以像C语言那样用指针操纵数组。但前提是必须有fixed (int* p = 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的源代码,因为有些类型长度不一样,如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);
            }                
        }
    复制代码

    (*) stackalloc

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

    复制代码
        class MyClass
        {
            
    public int val;
        }

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

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

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

  • 相关阅读:
    软件设计和开发是手艺活也是艺术活
    学界老师和业界专业人员的紧密合作才能促进软件设计开发教学的进步
    最简单的 GitExtensions 教程(持续更新中)
    最简单的 IntelliJ IDEA 中使用 GitHub 进行版本控制教程(持续更新中)
    工作室成员 GitHub 地址集中贴(按发布时间先后排序)
    使用 Visual Studio Code 运行 C# 及 Java 程序
    推荐一个非常好的 IntelliJ IDEA 教程
    Commit message 和 Change log 编写指南(转自阮一峰的博客)
    关于编码规范的延伸资料(来自于福州大学陈世发同学的博客)
    【扩展阅读】提问的智慧(转自福州大学陈世发同学的评论)
  • 原文地址:https://www.cnblogs.com/mingxuantongxue/p/3803169.html
Copyright © 2020-2023  润新知