【C#进阶】C# 不安全代码
序号 | 系列文章 |
---|---|
20 | 【C#进阶】C# 泛型 |
21 | 【C#进阶】C# 匿名方法 |
22 | 【C#进阶】C# 多线程 |
文章目录
- 前言
- 1、什么是不安全代码?
- 2、如何编译不安全代码?
- 3、指针类型
- 4、指针执行的运算符和语句
- 5、固定大小的缓冲区
- 6、函数指针
- 7、不安全代码的总结
- 结语
前言
📔 大家好啊,我是哈桑c,本文为大家介绍 C# 中的非托管代码。
1、什么是不安全代码?
不安全代码又称非托管代码,在 C# 中不安全的代码可以使用指针、分配和释放内存块,以及使用函数指针调用方法。注意不安全的代码并不一定是危险的,只是其安全性不可验证的代码。
在 C# 程序中可以使用 unsafe 上下文来编写不安全的代码,一般我们编写的大部分 C# 代码都是“可验证的安全代码”。可验证的安全代码是指 .NET 框架可验证代码是否安全。
代码示例: (使用 unsafe 上下文一段输出指针变量的代码。)
unsafe // unsafe 关键字声明不安全代码
{int num1 = 20;int* p = &num1;Console.WriteLine($"数据是: {num1} ");Console.WriteLine($"数据地址是: {(int)p}");Console.ReadLine();
}/*
输出:数据是: 20数据地址是: 5763444*/
从上例中看出,在 unsafe 关键字声明的语句块内的代码可以使用指针输出 num 对象的数据地址。
using System;// unsafe 修饰符可以修饰整个类
public unsafe class UnsafeCodeSample
{// 也可以修饰整个方法,通常只需要声明其中一种,这里为了方便演示。static unsafe void Main(string[] args){int num1 = 20;int* p = &num1;Console.WriteLine($"数据是: {num1} ");Console.WriteLine($"数据地址是: {(int)p}");Console.ReadLine();}
}/*
输出:数据是: 20数据地址是: 41414304*/
在声明方法签名时,也可以使用 unsafe 修饰符声明整个方法或类为不安全代码。本文主要使用前者演示不安全代码的使用。
2、如何编译不安全代码?
在 Visual Studio 中右击报错的项目选择属性,找到生成里面的 允许使用“unsafe"关键字编译的代码 ,勾选即可。
点击查看详细步骤演示。
3、指针类型
在 C# 中,数据类型除了可以是值类型或引用类型之外,还可以是指针类型。可以使用 * 符号来声明类型变量的地址,比如 Type* 类型的指针变量的值为 Type 类型的变量的地址。
注意指针类型只能在不同的指针类型之间以及指针类型和整型之间进行转换,而且指针类型不能指向引用对象。
指针类型的声明语法:
当在同一声明中声明多个指针时,星号 (*) 仅与基础类型一起写入, 而不是用作每个指针名称的前缀。
int* p1, p2, p3;
int *p1, *p2, *p3; // 在C#中无效
以一个表格展示指针类型声明的示例:
示例 | 描述 |
---|---|
int* p | p 是指向整数的指针。 |
int** p | p 是指向整数的指针的指针。 |
int*[] p | p 是指向整数的指针的一维数组。 |
char* p | p 是指向字符的指针。 |
void* p | p 是指向未知类型的指针。 |
代码示例:
unsafe
{int num1 = 11;int* p1 = &num1;// 指向整数的指针。 Console.WriteLine($"指向整数num1的地址为{(int)p1}");int** p2 = &p1;// 指向整数的指针的指针。Console.WriteLine($"指向整数num1的指针的地址为{(int)p2}");int*[] p3 = new int*[] {p1};// 指向整数num1的指针的一维数组 Console.WriteLine($"指向整数num1的指针的一维数组为{p3}");char c1 = 'c';char* p4 = &c1;// 指向字符的指针Console.WriteLine($"指向字符的地址为{(int)p4}");void* p5 = &p4;// 指向未知类型的指针 Console.WriteLine($"指向未知类型的地址为{(int)p5}");/*
输出:指向整数num1的地址为46002224指向整数num1的指针的地址为46002220指向整数num1的指针的一维数组为System.Int32*[]指向字符的地址为46002208指向未知类型的地址为46002204
*/
}
4、指针执行的运算符和语句
以一个表格展示可在不安全的上下文中对指针执行的运算符和语句:
运算符/语句 | 使用 |
---|---|
* | 执行指针间接寻址。 |
-> | 通过指针访问结构的成员。 |
[] | 为指针建立索引。 |
& | 获取变量的地址。 |
++ 和 – | 递增和递减指针。 |
+ 和 - | 执行指针算法。 |
==、!=、<、>、<= 和 >= | 比较指针。 |
stackalloc | 在堆栈上分配内存。 |
语句 | 临时固定变量以便找到其地址。 |
5、固定大小的缓冲区
在 C# 中,fixed 关键字可以创建在数据结构中具有固定大小的数组的缓冲区。通俗的讲就是 fixed 关键字能够将指定的数组给固定住,并返回固定后的指针。这是因为堆上对象的实际地址是不固定而受 GC1 控制的。当需要编写与其他语言或平台的数据源进行互操作的方法时,就可以使用固定大小的数组的缓冲区。
使用 fixed 的唯一限制就是数组的类型必须为 bool、byte、char、short、int, long、sbyte、ushort、uint、ulong、float 或 double 。
代码示例:
using System;public class UnsafeCodeSample
{// 在访问修饰符后面声明unsafe修饰符public unsafe static void Main(){int[] list1 = { 10, 100, 200 };fixed (int* ptr = list1) /* 显示指针中数组地址 */for (int i = 0; i < 3; i++){Console.WriteLine($"list1的地址[{i}]={ (int)(ptr + i)}");Console.WriteLine($"list1的元素值[{i}]={*(ptr + i)}");}}
}/*
输出:list1的地址[0]=90230144list1的元素值[0]=10list1的地址[1]=90230148list1的元素值[1]=100list1的地址[2]=90230152list1的元素值[2]=200
*/
从上例的输出结果可以看出,使用 fixed 关键字可以使用指针变量访问数组数据。
固定大小的缓冲区与常规数组的区别体现在以下几个方面:
- 需要在 unsafe 上下文中使用。
- 只能是结构的实例字段。
- 它们始终是矢量或一维数组。
- 声明固定大小的数组时应包括长度,如 fixed char id[8]。 不能使用 fixed char id[]。
6、函数指针
函数指针指的是函数编码后的指令在内存中的首个地址。在 C# 中的 delegate 类型用来定义安全函数指针对象, 而 delegate* 语法可以用来定义函数指针。
代码示例:
using System;public unsafe class FunctionPointer
{public static T UnsafeCombine<T>(delegate*<T, T, T> combinator, T left, T right) =>combinator(left, right);static int localMultiply(int x, int y) => x * y;static void Main(string[] args){int product = UnsafeCombine(&localMultiply, 6, 4);Console.WriteLine(product);}
}/*
输出:24
*/
在上面的示例中,我们将 localMultiply 方法的地址当作参数传递给了函数指针 combinator ,并成功执行输出了结果 24。
7、不安全代码的总结
不安全代码的属性可总结为以下几点:
- 可将方法、类型和代码块定义为不安全。
- 有时候通过移除数组检测,不安全代码可提高程序的性能。
- 不安全代码常用于调用需要指针的本机函数时。
- 使用不安全代码需要承担对应的安全风险和稳定性风险。
- 运行不安全代码需要使用允许不安全代码的编译器。
点击了解更多不安全代码的使用。
结语
📚 以上就是 C# 不安全代码的介绍啦,希望对大家有所帮助。感谢大家的支持。
GC: 全称为 garbage collection,中文名称为垃圾回收机制,是 .net 框架中对内存管理的一种技术。 ↩︎
相关文章:

【C#进阶】C# 不安全代码
序号系列文章20【C#进阶】C# 泛型21【C#进阶】C# 匿名方法22【C#进阶】C# 多线程文章目录前言1、什么是不安全代码?2、如何编译不安全代码?3、指针类型4、指针执行的运算符和语句5、固定大小的缓冲区6、函数指针7、不安全代码的总结结语前言 Ὅ…...

Docker安装部署ElasticSearch
1.部署单点ElasticSearch 1.1.创建网络 因为我们还需要部署kibana容器,因此需要让ElasticSearch和kibana容器互联。这里先创建一个网络: docker network create es-net1.2.拉取镜像 考虑到ElasticSearch的兼容性,这里ElasticSearch、kiba…...

【新2023Q2模拟题JAVA】华为OD机试 - 快递业务站
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:快递业务站 题目 快递业务范…...

OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换
OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换1.傅里叶变换理论概述2.Numpy实现傅里叶变换2.1 傅里叶变换2.2 傅里叶逆变换2.3 高通滤波3.OpenCV实现傅里叶变换3.1 实现傅里叶变换3.2 实现傅里叶逆变换3.3 低通滤波作者:Xiou 1.傅里叶变换…...
线段树合并
前置知识:权值线段树,动态开点。 引入 我们先来看一道题: 永无乡包含 nnn 座岛,给出每座岛的重要度的排名,名次用 111 到 nnn 来表示。一开始有 mmm 条边连接,接下来有 qqq 次操作。操作分两种ÿ…...

研发效能 | DevOps如何改变游戏公司工作方式?
如果你是游戏开发者,那么在过去几年里,你可能会觉得有人给了你一把双刃剑。 整个行业不断蓬勃发展,但玩家的预期值也越来越高。玩家们总是希望游戏体验能够更快、更真实、更具创造性。此外,他们还希望能够定期推出新的游戏和更新…...
Mongo聚合和Springboot整合Mongo聚合
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。 语法格式:db.集合名称.aggregate({管道:{表达式}}) 常用管道如下: $group: 将集合中的⽂…...

第06章_索引的数据结构
第06章_索引的数据结构 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,目…...

不确定的市场,确定的增长,海尔智家2022全球再逆增
文|螳螂观察 作者| 余一 上市公司2022年年报逐渐进入密集披露期,在当前的年报季窗口,各家公司的业绩情况被高度关注。 3月30日晚,海尔智家发布了2022年财报。财报显示,2022年海尔智家实现收入2435.14亿元,同比增长7…...

测试老鸟手把手教你python接口自动化测试项目实战演示
目录 前言 一、项目准备 二、项目流程 三、完整代码 四、总结 前言 在进行接口自动化测试项目实战之前,我们需要先了解什么是接口自动化测试。接口自动化测试是通过自动化脚本模拟用户请求和服务器响应的过程,以检测接口是否符合预期,确…...

一起来学5G终端射频标准(Coherent UL-MIMO测试要求)
01 — Coherent UL-MIMO测试要求 首先什么是Coherent?它的英文释义是:(of ideas, thoughts, argument, theory, or policy) logical and consistent,翻译过来就是:(看法、思想、论证、理论或政策等&…...

计算广告(五)
Nobid Nobid(在某手有时也叫MCB,在Facebook叫Lowest Cost)是指广告主不用(也不能)对转化成本进行出价,而是出一个预算(大多数是日预算),然后投放平台的目标是在时间范围…...

排序输入的高效霍夫曼编码 | 贪心算法 3
前面我们讲到了 贪心算法的哈夫曼编码规则,原理图如下: 如果我们知道给定的数组已排序(按频率的非递减顺序),我们可以在 O(n) 时间内生成霍夫曼代码。以下是用于排序输入的 O(n) 算法。1.创建两个空队列。2.为每个唯一…...

奇异值分解(SVD)和图像压缩
在本文中,我将尝试解释 SVD 背后的数学及其几何意义,还有它在数据科学中的最常见的用法,图像压缩。 奇异值分解是一种常见的线性代数技术,可以将任意形状的矩阵分解成三个部分的乘积:U、S、V。原矩阵A可以表示为&#…...
Java如何从yml文件获取对象
目录一、背景二、application.yml三、ChinaPersonFactory.java四、使用示例一、背景 在 SpringBoot 中,我们可以使用 Value 注解从属性文件(例如 application.yml 或 application.properties)中获取配置信息,但是只能获取简单的字…...

vue使用tinymce实现富文本编辑器
安装两个插件tinymce和 tinymce/tinymce-vue npm install tinymce5.10.3 tinymce/tinymce-vue5.0.0 -S 注意: tinymce/tinymce-vue 是对tinymce进行vue的包装,主要作用当作vue组件使用-S保存到package.json文件 2. 把node_modules/tinymce下的目录&a…...
yolov4实战训练数据
1、克隆项目文件 项目Github地址:https://github.com/AlexeyAB/darknet 打开终端,克隆项目 git clone https://github.com/AlexeyAB/darknet.git无法克隆的话,把https修改为git git clone git://github.com/AlexeyAB/darknet.git修改Makef…...

第十四章 DOM的Diff算法与key
React使用Diff算法来比较虚拟DOM树和真实DOM树之间的差异,并仅更新必要的部分,以提高性能。key的作用是在Diff算法中帮助React确定哪些节点已更改,哪些节点已添加或删除。 我们以案例来说明。 使用索引值和唯一ID作为key的效果 1、使用索引…...
MySQL调优
MySQL调优常见的回答如何回答效果更好业务层的优化如果只能用mysql该如何优化代码层的优化SQL层面优化总结常见的回答 SQL层面的优化——创建索引,创建联合索引,减少回表。再有就是少使用函数查询。 回表指的是数据库根据索引(非主键&#…...

《Flutter进阶》flutter升级空安全遇到的一些问题及解决思路
空安全出来挺久了,由于业务需求较紧,一直没时间去升级空安全,最近花了几天去升级,发现其实升级也挺简单的,不要恐惧,没有想象中的多BUG。 flutter版本从1.22.4升到3.0.5; compileSdkVersion从1…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...