type
status
date
slug
summary
tags
category
icon
password
- 使用指针的前提条件
- 必须在unsafe上下文中
- 必须使用AllowUnsafeBlocks编译器(Unity中为项目设置打开 Allow ‘unsafe’ code 选项)
- 写作 引用类型* (type* identifier 或者未知引用类型的 void* identifier)
- 引用类型必须为非托管类型
- 使用fixed语句防止GC重新定位可移动变量,并声明指向该变量的指针
- 固定变量的地址在语句的持续时间内不会更改
- 只能在相应的fixed语句中使用声明的指针,该指针是只读的
- 由于fixed语句中定义的指针不能动,可以在fixed域内使用另一个指针指向该指针进行移动in
- void* p由于不知道目标数据类型,不能用*p来获取内容,但是可以通过强制转换到其他指定类型来获取,如(int*)p
- 方法间传递指针会导致未定义的行为。考虑使用in\out\ref或是以函数结果的方式,将指针传至区域变量。如果已经在静态区域中设置指针,则该指针指向的变量可能是不固定的
- 运算符
运算符 | 解释 | 样例 | 结果 |
* | 执行指针间接取值 | *p | 指针p指向的数据内容 |
-> | 透过指针存取结构的成员 | p->t | 相当于(*p).t,即获得指针p指向的数据类型中的t变量的数据 |
[] | 索引指针 | *p[10] | 指针数组p的第十个指针指向的数据内容 |
& | 指针地址 | &p | 返回指针p的地址 |
逻辑运算符(==等) | 判断指针地址逻辑 | p==t | p指针指向地址是否等于t |
stackalloc | 在堆栈上配置内存 | Span<int> number = stackalloc int[length]; | 方法中使用,在堆上分配内存块,在方法返回时自动丢弃。不能显式释放使用stackalloc分配的内存,此内存块不受GC影响,也不需要fixed固定。
分配给Span<T>或者ReadOnlySpan<T>时不需要unsafe |
fixed语句 | 临时固定变量以找到其地址 | ㅤ | ㅤ |
- fixed关键字用于创建数据结构中固定大小的数组的缓冲区,用法:private fixed char name[30]
- C#的安全代码声明的数组是不包含数组内元素的,只有对这些元素的引用
- 在安全代码里, struct中如果有可变数组,struct的大小并不依赖数组长度,因为在这里数组是引用
- 结构可以在不安全代码中包含嵌入的固定大小数组,即fixed修饰的数组可以放在unsafe struct中
- 此时使用fixed语句获取指向第一个元素的指针,即下面代码中charPtr指向fixedBuffer的第一个元素指针
- 固定大小的缓冲区相比常规数组的特性
- 只能用于unsafe
- 只能是结构的实例字段
- 始终是矢量或一维数组
- 声明应包括长度
- 使用指针复制字节数组
- unsafe关键字+Copy方法+fixed语句声明指向源数组与目标数组的指针并固定在内存中以避免被GC
- C#提供delegate定义安全函数指针对象,调用委托时需要实例化委托拍省得类型并虚拟方法调用Invoke,该方式使用IL指令callvirt
- IL指令calli效率更高,需要改用delegate* 实现,以下是两种不同实现
- 如何使用Unsafe的高效版本
- 规则
- 函数只能在unsafe{}中声明
- 只能在unsafe中调用delegate*
- 只能在static函数中用&获取函数地址
- delegate* 表示声明是函数指针,方法组分配给函数指针时,&表示操作采用方法的地址
- 使用managed和unmanaged为delegate* 指定 调用约定(?)
- 作者:Reguluz
- 链接:https://reguluz.cn/article/c-sharp-unsafe-1
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。