.C#可否对内存进行直接的操作

C#中直接操作内存的方法 C#中直接操作内存的方法。Marshal、GChandle、Fixed机制。 阅读详情

摘要
可以使用指针
在这篇文章中我将简单的描述C#的一个特性指针和所谓的不安全代码。这个标题和C++程序员更接近一些。此外,在Java中我们没有找到这样的特性。

托管代码

一般来说你在写任意一个C#程序的时候,你都是在创建托管代码。托管代码是在Common Language Runtime (CLR)控制下执行的,CLR使得程序员不需要管理内存和关心内存的分配和回收。CLR也允许你写非安全代码 (unsafe code)。

非安全代码

非安全代码就是不在 CLR 完全控制下执行的代码,它有可能会导致一些问题,因此他们必须用 “unsafe” 进行表明:

...
unsafe
{
...
// unsafe context: can use pointers here
...
}
...
 
在其他一些地方也可以使用关键字 ‘unsafe’,例如我们可以将类或方法表明为非安全的:

unsafe class Class1 {}
static unsafe void FastMove ( int* pi, int* pdi, int length) {...} 

‘unsafe’ 关键字的必要性是它可以防止程序员的一些意外的用法。你可能会问既然是不安全的为什么还有人要用它。答案就是有时候,在有些情况下,还需要用到指针。

指针

指针是一种用来存储其他变量地址的特殊的变量,如果你把第一个变量的地址赋给第二个变量,你可以说第一个变量是指向第二个,CLR支持3种指针类型:受托管指针, 非托管指针和非托管函数指针。受托管指针存储在堆上的托管块的引用,一个非托管指针是传统的C++指针并且每次使用必须要放在unsafe代码块中,一个非托管函数指针也是指向函数地址的传统的C++指针(delegates 可以被看做是非托管函数指针).

你可以像下面这样的声明来创建指针:

类型* 变量_名称; 

既然类型可以是任意一个非引用类型并且不包含引用类型字段,它只能是:sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool 和枚举类型以及其他指针类型,也可以是任何用户自定义的包括非托管类型字段的结构体.

下面是不同类型指针声明的示例:

int* pi //declaration a pointer to integer variable
float* pf, pq // two pointers to float variables. Not *pf, *pq
char* pz // pointer to char

就像前面说的非托管代码CLR是不能验证的,为了编译你需要指定 /unsafe 编译选项,如果你是使用的是Microsoft Visual Studio你需要在项目选项中把 'Allow unsafe code block'设置成 True。

指针的基本用法

还有一些与指针紧密联系的操作符,那就是 & 操作符,& 返回它所操作对象的地址。

例如:
unsafe
{
int* pi;
int x = 1;
pi = &x;
System.Console.WriteLine("Value of x is: " + *pi);
}

在这个例子中我们创建了2个变量,’pi’是指向int的指针,’x’是int,然后我们将’x’在内存中的地址赋予’pi’,理解我们放在 ’pi’ 变量中的是 ’x’的地址而不是’x’的值非常重要 (使用: pi = x 将返回错误 "Cannot implicitly convert type 'int' to 'int*'")

编译后执行将会输出:

Value of x is: 1 

指针可以接受 null 值,也可能使用 void 指针类型,下面的代码可以正常编译:

unsafe
{
nt x = 10;
void* px = &x;
double *pd = (double*)px;
}
 
fixed
关键字和垃圾回收

在 C# 中使用指针需要比在 C++种更加注意。这是因为垃圾回收器(g.c.)会运行内存清理,在清理的过程中,g.c.会改变对象的物理内存位置,如果 g.c.改变了对象的位置指针将指向错误的内存位置。为了避免这样的问题(已经与垃圾回收器连接),C# 包含 'fixed' 关键字. 它通知系统不要让垃圾回收器重新部署对象。

'fixed' 示例:

// pt is a managed variable, subject to g.c.
Colour cl = new Colour();
// must use fixed to get address of cl.R
fixed ( int* pi = &cl.R)
{
*pi = 1;
}

初始化同一类型的多个指针:

fixed (byte* pb = sarr, pd = darr) {...}

初始化不同类型的指针:

fixed (int* pi = &cl.G)
fixed (double* pd = &array[10])

如果我们忘了 ’fixed’ 关键字编译器会给我们相应的警告,但它没有智能到在下面的情况中也会警告我们。下面的代码有一个严重的Bug尽管编译很正常。

class Test
{
public int x;
}
unsafe class SimpleTest
{
[STAThread]
static void Main(string[] args)
{
Test test = new Test();
int* pi;
fixed (int* px = &test.x)
{
*px = 100;
pi = px;
}
Console.WriteLine("before g.c.: " + *pi);
System.GC.Collect(2);
Console.WriteLine("after g.c.: " + *pi);
}
}

在我的机器上结果是:

before g.c.: 100
after g.c.: 132 

我们可以看到同一个指针有两个不同的值,事实上在'before g.c.' 和 'after g.c.' 能得到不同结果的可能性非常小,because probability of starting garbage collector is very little. 但是作为一个规则我们应该避免在fixed块以外使用指针,我们的情况是每次在fixed块外使用 ’pi’ 指针都有可能产生难以诊断的错误。

C# 指针和 WinApi

使用指针最重要的好处就是可以与其他二进制代码进行交互。许多 WinApi 函数都使用指针,例如GetComputerName (Kernel32.lib.)可以提供我们的计算机的名称。

BOOL GetComputerName(LPTSTR lpBuffer, // computer name
LPDWORD lpnSize // size of name buffer);

下面的程序演示如何使用GetComputerName:

[System.Runtime.InteropServices.DllImport("Kernel32")]
static extern unsafe bool GetComputerName(byte* lpBuffer,long* nSize);
static void Main()
{
byte[] buffor = new byte[512];
long size = buffor.Length;
unsafe
{
long* pSize = &size;
fixed (byte* pBuffor = buffor)
{
GetComputerName(pBuffor,pSize);
}
}
System.Text.Encoding textEnc = new System.Text.ASCIIEncoding();
System.Console.WriteLine("Computer name: {0}",textEnc.GetString(buffor));
}

结论

我们已经看到指针是C#语言中非常有用的部分,使用指针并不难但是要非常小心,因为有可能会导致难以诊断的问题,使用指针会扰乱垃圾回收器的功能,特别当我们在程序中大量使用指针。因此在之用指针之前我们应该多考虑,或者尝试其他的解决办法。

 
C#读写内存操作方式 public class MemoryHelp { [DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")] public static extern bool ReadProcessMemory ( IntPtr lpProcess, 阅读详情

相关推荐

C# 内存操作常用函数

写这篇文章是有一个起因的... 最近在学socket编程 翻源代码的时候 无意发现一个没有用过的函数Marshal.UnsafeAddrOfPinnedArrayElement() 它的原形如下: public static IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index); 这个静态函数的作用是返回一个数组第index

颠倒酱的数据研究 3485

C#可否对内存进行直接的操作?

C#可否对内存进行直接的操作?答:C#可以直接对内存进行操作。但是默认情况下,为了保持类型安全,C#不支持指针运算。不过,通过使用unsafe关键字,可以定义可使用指针的不安全上下文。 转载于:https://www.cnblogs.com/melao2006/p/4233902.html...

adiking520110的博客 490

C# 操作内存案例

<br />1 //C#读取内存例子 <br />  2 <br />  3 using System;<br />  4 using System.Collections.Generic;<br />  5 using System.Text;<br />  6 using System.Runtime.InteropServices;<br />  7 using System.Diagnostics;<br />  8 using System.Management;<br />  9 <br />1

杨义贤心灵驿站 1580

c#可否对内存直接操作

C#在unsafe 模式下可以使⽤指针对内存进⾏操作, 但在托管模式下不可以使⽤指针,C#NET默认不运⾏。带指针的,需要设置下,选择项⽬右键->属性->选择⽣成->“允许不安全代码”打勾->保存。

qq_61141142的博客 197

C# Windows API内存操作:从“内存小白”到“指针大神”

C#内存操作指南:从基础到实战 本文系统介绍了C#操作Windows内存的完整方法体系。首先讲解了内存基础知识(栈/堆、值/引用类型、unsafe代码),然后通过10个步骤详细演示了如何使用P/Invoke和Win32 API进行内存操作,包括进程打开、内存读写、资源释放等核心操作。文章特别强调了内存管理的重要原则,提供了错误处理方案和性能优化技巧(如Span<T>使用、对象池等),并针对常见问题给出解决方案。最后通过对比表清晰展示了托管与非托管内存的区别,为开发者提供全面的内存操作参考方案。

java专栏 1119

C# 内存操作技巧与风险防范指南

在C#中,拷贝对象时,我们可以执行浅拷贝或深拷贝。浅拷贝指的是复制对象的引用,而不是对象本身,所以原始对象和复制的对象会指向同一个内存地址。深拷贝则复制对象本身,包括它的所有成员,创建一个完全独立的新对象。浅拷贝:仅复制对象的引用(地址),而不复制实际的数据。对象的内存地址是相同的。深拷贝:复制对象的实际数据,创建一个新的对象实例,且两个对象在内存中的地址不同。

weixin_42575109的博客 987

C# 可否对内存进行直接的操作?

可以,用unsafe。用的时候记得在项目属性(Properties)->生成(Build)->常规(General)中钩上允许不安全代码 (Allow unsafe code)。否则会出现这个错误:Unsafe code may only appear if compiling with /unsafe。 // compile with: /unsafe using Syst...

weixin_30345577的博客 329

SNN目标识别MNIST

总体来说这篇论文提出的方法用了多种更精密的细节,如LIF膜电位公式,三种STDP方法,但我觉得还可以有很大的改进,比如输入层全连接到兴奋层,兴奋层通过抑制层实现的侧向抑制,抑制层不参与学习等等。尤其是兴奋层通过抑制层实现侧向抑制这里,当神经元兴奋时,通过抑制层再倒回兴奋层,所抑制的已经经过一了一段时间的延迟。如有错误,请不吝赐教。

m0_74982304的博客 1262

C#面:C# 是否可以对内存直接进行操作

使用指针可以绕过 C# 的类型安全检查,因此需要谨慎使用,并且只有在必要的情况下才应该使用指针操作。在上面的示例中,我们使用类 int 型的指针来存储变量的地址。通过可 *pointer 以访问指针所指向的内存位置的值。通过可*pointer = 20 以修改指针所指向的内存位置的值。需要注意的是,使用指针操作可能会导致内存泄漏、非法访问等问题,因此在使用指针时需要非常小心,并且确保代码的安全性和稳定性。在C#中,可以通过使用指针来对内存进行直接操作。

那个那个鱼的博客 984

RocketMq面板访问异常 com.alibaba.fastjson.JSONException: not close json text, token : string

rocketmq JSONException: not close json text, token : string 问题解决

qq_21067307的博客 5573

告别远程控制弹窗:免Root实现投射与录制敏感信息自动授权

本文针对Android远程控制中频繁出现的‘在投射和录制时显示敏感信息’弹窗问题,提供了一套免Root的自动化解决方案。通过结合Shizuku与App Ops两款工具,无需破解系统即可静默授予屏幕投射与录制权限,从而实现稳定、无干扰的远程协助、家庭监控或自动化测试,彻底告别手动授权弹窗的烦恼。

qsc9012345的博客 718

C#可否对内存进行直接的操作

C#可否对内存进行直接的操作 ?可以使用指针在这篇文章中将描述C#的一个特性指针和所谓的不安全代码。非安全代码       非安全代码就是不在 CLR 完全控制下执行的代码,它有可能会导致一些问题,因此他们必须用 “unsafe” 进行表明:       unsafe       {       ...       // unsafe context: can use pointers her

言出必行 5031

从平面到立体:一张图看懂MOSFET、FinFET到GAAFET的演变史(附结构对比图)

本文深入解析了半导体晶体管从平面MOSFET到三维FinFET,再到全环绕栅极GAAFET的技术演进历程。通过结构对比图和物理原理分析,揭示了每一次创新如何解决短沟道效应等关键挑战,推动芯片性能提升。特别关注GAAFET作为最新技术突破的架构特点和性能优势。

weixin_30892037的博客 698

2021-05-16 C#.NET面试题 c#可否对内存直接操作

c#可否对内存直接操作 C#在unsafe 模式下可以使用指针对内存进行操作, 但在托管模式下不可以使用指针,C#NET默认不运行带指针的,需要设置下,选择项目右键->属性->选择生成->“允许不安全代码”打勾->保存 ...

微软MVP Eleven 6万+

【数据库】银行/信贷业务测试工作中涉及的数据库表格

银行/信贷业务测试工作中涉及的数据库表格,金融信贷测试人必看!

孤之鹜的博客 1172

提升JVM性能:CMS垃圾回收器的优化分析与案例研究

本文介绍了CMS(Concurrent Mark-Sweep)垃圾回收器的工作原理、优缺点及常见问题,并通过具体案例分析了其优化策略。重点探讨了CMS的各个阶段,包括标记、并发清理和重标记,分析了可能导致性能瓶颈的因素如停顿时间过长和内存碎片化。文章还分享了调整垃圾回收参数、结合其他垃圾回收器以及内存优化等方法,帮助提高CMS的回收效率和性能。最后,文章展望了随着JVM发展,结合新一代垃圾回收器优化的趋势,助力Java应用在高并发环境下的性能提升。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 175万+

47、C#可否对内存进⾏直接的操作?

C# 可以通过几种方式对内存进行直接操作,尽管它主要是一门托管语言,内存管理通常由.NET运行时自动处理。

qq_27678663的博客 1039

MinerU 系列教程 第六课:VLM 后端 - 视觉语言模型的力量

本篇教程将深入 VLM 后端的端到端推理架构。在上一课中我们看到 Pipeline 后端如何用 7+ 个专用模型组成流水线,本课将展示一种截然不同的设计理念 —— 用一个视觉语言模型(VLM)完成所有识别任务。你将了解 6 种推理引擎的选择与配置、MinerUClient 统一接口、二步提取策略,以及 VLM 原始输出如何转换为 MinerU 的标准 Middle JSON 格式。

weixin_43674738的博客 205

C#是否可以对内存直接进行操作?

这个问题比较难回答,也是个很大的问题。但是可以这样问答。C#是可以对内存进行直接操作的,虽然很少用到指针,但是C#是可以使用指针的,在用的时候需要在前边加unsafe,,在.net中使用了垃圾回收机制(GC)功能,它替代了程序员,不过在C#中不可以直接使用finalize方法,而是在析构函数中调用基类的finalize()方法。

X_X_OO的博客 3743

PyTorch生成式人工智能(25)——基于Transformer实现机器翻译

不同于循环神经网络 (RNN) 按顺序处理数据,Transformer 以并行的方式处理输入数据(例如句子)。这种并行处理提高了效率,但并未使其能够识别输入的顺序。为了解决这个问题,Transformer 向输入的词嵌入中添加了位置编码。这些位置编码是分配给输入序列中每个位置的独特向量,其维度与输入词嵌入对齐。本节将以英语到法语的翻译为例,通过介绍如何训练 Transformer 模型将英语句子转换为法语,深入理解 Transformer 的架构及自注意力机制的运作方式。

盼小辉丶的博客 2752

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

从C++看C#托管内存与非托管内存

一个exe文件,在没有运行时,其磁盘存储空间格式为。加载为内存后,其进程内存模式增加为。我们重点讨论堆区。

sdgfafg_25的博客 1639

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C# 中 LINQ to Objects 如何操作内存集合

与 LINQ to SQL、LINQ to Entities 等针对外部数据源(如数据库)的 LINQ 提供器不同,LINQ to Objects 操作完全局限在内存之中,不涉及网络通信、数据库事务等外部操作相关的复杂性,它的重点就是高效利用内存、优化对内存中已有集合的查询逻辑,提供快速且灵活的数据处理方式。这样的筛选操作时,LINQ to Objects 会遍历内存集合中的每个元素,然后根据给定的条件(例如上述代码中的判断是否为偶数)来决定元素是否应该包含在最终的查询结果中。

学习和分享 1763

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

上一篇: XML Schema 与 XML DTD的技术比较与分析
下一篇: C#之修饰符-----abstract
NETZHOU
博客等级 码龄24年 10粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值